diff --git a/core/src/main/java/org/teavm/ast/BoundCheckExpr.java b/core/src/main/java/org/teavm/ast/BoundCheckExpr.java new file mode 100644 index 000000000..8d682233d --- /dev/null +++ b/core/src/main/java/org/teavm/ast/BoundCheckExpr.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019 konsoletyper. + * + * 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.ast; + +import java.util.Map; + +public class BoundCheckExpr extends Expr { + private Expr index; + private Expr array; + private boolean lower; + + public Expr getIndex() { + return index; + } + + public void setIndex(Expr index) { + this.index = index; + } + + public Expr getArray() { + return array; + } + + public void setArray(Expr array) { + this.array = array; + } + + public boolean isLower() { + return lower; + } + + public void setLower(boolean lower) { + this.lower = lower; + } + + @Override + public void acceptVisitor(ExprVisitor visitor) { + visitor.visit(this); + } + + @Override + protected Expr clone(Map cache) { + Expr known = cache.get(this); + if (known != null) { + return known; + } + BoundCheckExpr copy = new BoundCheckExpr(); + cache.put(this, copy); + copy.setIndex(index.clone(cache)); + copy.setArray(array != null ? array.clone(cache) : null); + copy.setLower(lower); + return copy; + } +} diff --git a/core/src/main/java/org/teavm/ast/ExprVisitor.java b/core/src/main/java/org/teavm/ast/ExprVisitor.java index 3a4fba052..1dc82f080 100644 --- a/core/src/main/java/org/teavm/ast/ExprVisitor.java +++ b/core/src/main/java/org/teavm/ast/ExprVisitor.java @@ -45,4 +45,6 @@ public interface ExprVisitor { void visit(CastExpr expr); void visit(PrimitiveCastExpr expr); + + void visit(BoundCheckExpr expr); } diff --git a/core/src/main/java/org/teavm/ast/RecursiveVisitor.java b/core/src/main/java/org/teavm/ast/RecursiveVisitor.java index b3bc42d44..8c3b42873 100644 --- a/core/src/main/java/org/teavm/ast/RecursiveVisitor.java +++ b/core/src/main/java/org/teavm/ast/RecursiveVisitor.java @@ -227,4 +227,14 @@ public class RecursiveVisitor implements ExprVisitor, StatementVisitor { public void visit(MonitorExitStatement statement) { statement.getObjectRef().acceptVisitor(this); } + + @Override + public void visit(BoundCheckExpr expr) { + beforeVisit(expr); + expr.getIndex().acceptVisitor(this); + if (expr.getArray() != null) { + expr.getArray().acceptVisitor(this); + } + afterVisit(expr); + } } diff --git a/core/src/main/java/org/teavm/ast/analysis/LocationGraphBuilder.java b/core/src/main/java/org/teavm/ast/analysis/LocationGraphBuilder.java index 83795eed6..ab09546c2 100644 --- a/core/src/main/java/org/teavm/ast/analysis/LocationGraphBuilder.java +++ b/core/src/main/java/org/teavm/ast/analysis/LocationGraphBuilder.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.ConditionalExpr; import org.teavm.ast.ConditionalStatement; @@ -64,8 +65,8 @@ public final class LocationGraphBuilder { for (int terminal : visitor.nodes) { visitor.terminalNodes.set(terminal); } - TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph, - visitor.terminalNodes); + TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph + ); Map> builder = new LinkedHashMap<>(); for (int i = 0; i < graph.size(); ++i) { @@ -91,7 +92,7 @@ public final class LocationGraphBuilder { return result; } - private static TextLocation[][] propagate(TextLocation[] locations, Graph graph, BitSet terminal) { + private static TextLocation[][] propagate(TextLocation[] locations, Graph graph) { List> result = new ArrayList<>(); boolean[] stop = new boolean[graph.size()]; IntDeque queue = new IntArrayDeque(); @@ -338,6 +339,12 @@ public final class LocationGraphBuilder { nodes = distinct(exit); } + @Override + public void visit(BoundCheckExpr expr) { + super.visit(expr); + setLocation(expr.getLocation()); + } + private void setNode(int node) { for (int prevNode : nodes) { builder.addEdge(prevNode, node); diff --git a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java index 101a8e823..02616bb6f 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java +++ b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java @@ -24,6 +24,7 @@ import java.util.Map; import org.teavm.ast.ArrayType; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryOperation; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.ContinueStatement; import org.teavm.ast.Expr; @@ -54,6 +55,7 @@ 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.BoundCheckInstruction; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastIntegerInstruction; @@ -631,4 +633,16 @@ class StatementGenerator implements InstructionVisitor { stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); statements.add(stmt); } + + @Override + public void visit(BoundCheckInstruction insn) { + BoundCheckExpr expr = new BoundCheckExpr(); + expr.setLower(insn.isLower()); + expr.setIndex(Expr.var(insn.getIndex().getIndex())); + if (insn.getArray() != null) { + expr.setArray(Expr.var(insn.getArray().getIndex())); + } + expr.setLocation(insn.getLocation()); + assign(expr, insn.getReceiver()); + } } diff --git a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java index be6959911..d81b770e0 100644 --- a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java +++ b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java @@ -27,6 +27,7 @@ import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryOperation; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.CastExpr; import org.teavm.ast.ConditionalExpr; @@ -1036,6 +1037,28 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { } } + @Override + public void visit(BoundCheckExpr expr) { + pushLocation(expr.getLocation()); + try { + expr.getIndex().acceptVisitor(this); + Expr index = resultExpr; + + Expr array = null; + if (expr.getArray() != null) { + expr.getArray().acceptVisitor(this); + array = resultExpr; + } + + expr.setIndex(index); + expr.setArray(array); + + resultExpr = expr; + } finally { + popLocation(); + } + } + private Statement addBarrier() { SequentialStatement barrier = new SequentialStatement(); resultSequence.add(barrier); diff --git a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java index 2b7414c7f..699bfad66 100644 --- a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java +++ b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java @@ -100,7 +100,7 @@ class ReadWriteStatsBuilder { static class ConstantExtractor extends AbstractInstructionVisitor { private Object[] constants; - public ConstantExtractor(Object[] constants) { + ConstantExtractor(Object[] constants) { this.constants = constants; } diff --git a/core/src/main/java/org/teavm/backend/c/analyze/VolatileDefinitionFinder.java b/core/src/main/java/org/teavm/backend/c/analyze/VolatileDefinitionFinder.java index 83cd8589e..c37830da0 100644 --- a/core/src/main/java/org/teavm/backend/c/analyze/VolatileDefinitionFinder.java +++ b/core/src/main/java/org/teavm/backend/c/analyze/VolatileDefinitionFinder.java @@ -88,7 +88,6 @@ public class VolatileDefinitionFinder { private RecursiveVisitor handlerAnalyzer = new RecursiveVisitor() { StackElement surroundingTryCatches; - StackElement handlingTryCatches; @Override public void visit(TryCatchStatement statement) { diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java index 8d4e997db..77f6e73b6 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java @@ -41,6 +41,7 @@ import org.teavm.ast.ArrayType; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryExpr; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.CastExpr; import org.teavm.ast.ConditionalExpr; @@ -1420,6 +1421,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { popLocation(statement.getLocation()); } + @Override + public void visit(BoundCheckExpr expr) { + expr.getIndex().acceptVisitor(this); + } + private IntrinsicContext intrinsicContext = new IntrinsicContext() { @Override public CodeWriter writer() { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index f5debb032..4e139fbd8 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -30,6 +30,7 @@ import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryOperation; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.CastExpr; import org.teavm.ast.ConditionalExpr; @@ -1561,6 +1562,11 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { } } + @Override + public void visit(BoundCheckExpr expr) { + expr.getIndex().acceptVisitor(this); + } + private class InjectorContextImpl implements InjectorContext { private final List arguments; private final Precedence precedence = StatementRenderer.this.precedence; diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java index 51189f794..952c392af 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java @@ -28,6 +28,7 @@ import java.util.Set; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryExpr; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.CastExpr; import org.teavm.ast.ConditionalExpr; @@ -1365,6 +1366,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result = emptyStatement(statement.getLocation()); } + @Override + public void visit(BoundCheckExpr expr) { + expr.getIndex().acceptVisitor(this); + } + private WasmExpression negate(WasmExpression expr) { if (expr instanceof WasmIntBinary) { WasmIntBinary binary = (WasmIntBinary) expr; diff --git a/core/src/main/java/org/teavm/cache/AstIO.java b/core/src/main/java/org/teavm/cache/AstIO.java index 036aa3a67..37b21323e 100644 --- a/core/src/main/java/org/teavm/cache/AstIO.java +++ b/core/src/main/java/org/teavm/cache/AstIO.java @@ -29,6 +29,7 @@ import org.teavm.ast.AsyncMethodPart; import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryOperation; import org.teavm.ast.BlockStatement; +import org.teavm.ast.BoundCheckExpr; import org.teavm.ast.BreakStatement; import org.teavm.ast.CastExpr; import org.teavm.ast.ConditionalExpr; @@ -665,6 +666,19 @@ public class AstIO { throw new IOExceptionWrapper(e); } } + + @Override + public void visit(BoundCheckExpr expr) { + try { + output.writeUnsigned(expr.getArray() == null ? 27 : !expr.isLower() ? 26 : 25); + writeExpr(expr.getIndex()); + if (expr.getArray() != null) { + writeExpr(expr.getArray()); + } + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } + } } private TextLocation readLocation(VarDataInput input) throws IOException { @@ -1024,6 +1038,22 @@ public class AstIO { expr.setValue(readExpr(input)); return expr; } + case 25: + case 26: { + BoundCheckExpr expr = new BoundCheckExpr(); + expr.setLocation(lastReadLocation); + expr.setIndex(readExpr(input)); + expr.setArray(readExpr(input)); + expr.setLower(type == 25); + return expr; + } + case 27: { + BoundCheckExpr expr = new BoundCheckExpr(); + expr.setLocation(lastReadLocation); + expr.setIndex(readExpr(input)); + expr.setLower(true); + return expr; + } default: throw new RuntimeException("Unknown expression type: " + type); } diff --git a/core/src/main/java/org/teavm/cache/ProgramDependencyExtractor.java b/core/src/main/java/org/teavm/cache/ProgramDependencyExtractor.java index 7ad463039..23f7a0800 100644 --- a/core/src/main/java/org/teavm/cache/ProgramDependencyExtractor.java +++ b/core/src/main/java/org/teavm/cache/ProgramDependencyExtractor.java @@ -42,7 +42,7 @@ public class ProgramDependencyExtractor extends AbstractInstructionVisitor { return result; } - class AnalyzingVisitor extends AbstractInstructionVisitor { + static class AnalyzingVisitor extends AbstractInstructionVisitor { Set dependencies = new LinkedHashSet<>(); @Override public void visit(GetFieldInstruction insn) { dependencies.add(insn.getField().getClassName()); diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index d9176bb65..995cb725d 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -48,6 +48,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; @@ -738,6 +739,20 @@ public class ProgramIO { } } + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + try { + output.writeUnsigned(array == null ? 89 : !lower ? 88 : 87); + output.writeUnsigned(receiver.getIndex()); + output.writeUnsigned(index.getIndex()); + if (array != null) { + output.writeUnsigned(array.getIndex()); + } + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } + } + private void write(MethodHandle handle) throws IOException { switch (handle.getKind()) { case GET_FIELD: @@ -1205,6 +1220,18 @@ public class ProgramIO { } return insn; } + case 87: + case 88: + case 89: { + BoundCheckInstruction insn = new BoundCheckInstruction(); + insn.setReceiver(program.variableAt(input.readUnsigned())); + insn.setIndex(program.variableAt(input.readUnsigned())); + if (insnType != 89) { + insn.setArray(program.variableAt(input.readUnsigned())); + } + insn.setLower(insnType != 88); + return insn; + } default: throw new RuntimeException("Unknown instruction type: " + insnType); } diff --git a/core/src/main/java/org/teavm/dependency/AbstractInstructionAnalyzer.java b/core/src/main/java/org/teavm/dependency/AbstractInstructionAnalyzer.java index 8df10e176..bd9c2dba8 100644 --- a/core/src/main/java/org/teavm/dependency/AbstractInstructionAnalyzer.java +++ b/core/src/main/java/org/teavm/dependency/AbstractInstructionAnalyzer.java @@ -35,6 +35,8 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader { static final MethodReference CLONE_METHOD = new MethodReference(Object.class, "clone", Object.class); private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class, "", void.class); + private static final MethodReference AIOOB_INIT_METHOD = new MethodReference(ArrayIndexOutOfBoundsException.class, + "", void.class); static final MethodReference MONITOR_ENTER_METHOD = new MethodReference(Object.class, "monitorEnter", Object.class, void.class); static final MethodReference MONITOR_ENTER_SYNC_METHOD = new MethodReference(Object.class, @@ -272,6 +274,14 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader { methodDep.use(); } + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + MethodDependency methodDep = getAnalyzer().linkMethod(AIOOB_INIT_METHOD); + methodDep.addLocation(getCallLocation()); + methodDep.getVariable(0).propagate(getAnalyzer().getType(ArrayIndexOutOfBoundsException.class.getName())); + methodDep.use(); + } + protected abstract DependencyNode getNode(VariableReader variable); protected abstract DependencyAnalyzer getAnalyzer(); diff --git a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java index 9c0c68642..b7a1da1a7 100644 --- a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -213,4 +213,9 @@ public class InstructionReadVisitor implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { reader.monitorExit(insn.getObjectRef()); } + + @Override + public void visit(BoundCheckInstruction insn) { + reader.boundCheck(insn.getReceiver(), insn.getIndex(), insn.getArray(), insn.isLower()); + } } diff --git a/core/src/main/java/org/teavm/model/Interpreter.java b/core/src/main/java/org/teavm/model/Interpreter.java index be402332b..dbe087d8e 100644 --- a/core/src/main/java/org/teavm/model/Interpreter.java +++ b/core/src/main/java/org/teavm/model/Interpreter.java @@ -791,6 +791,11 @@ public class Interpreter { public void monitorExit(VariableReader objectRef) { } + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + variables[receiver.getIndex()] = variables[index.getIndex()]; + } + private Class asJvmClass(ValueType type) { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive) type).getKind()) { diff --git a/core/src/main/java/org/teavm/model/analysis/ClassInitializerAnalysis.java b/core/src/main/java/org/teavm/model/analysis/ClassInitializerAnalysis.java index 83c813d31..37b74152f 100644 --- a/core/src/main/java/org/teavm/model/analysis/ClassInitializerAnalysis.java +++ b/core/src/main/java/org/teavm/model/analysis/ClassInitializerAnalysis.java @@ -304,7 +304,6 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo { static class MethodInfo { MethodReference method; boolean complete; - Set recursiveCallers; Set classesWithModifiedFields; boolean anyFieldModified; diff --git a/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java b/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java index 953530ded..a6b682559 100644 --- a/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java +++ b/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java @@ -38,6 +38,7 @@ import org.teavm.model.instructions.AbstractInstructionVisitor; import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.ClassConstantInstruction; import org.teavm.model.instructions.CloneArrayInstruction; @@ -426,6 +427,13 @@ class NullnessInformationBuilder { markAsNotNull(insn.getReceiver()); } + @Override + public void visit(BoundCheckInstruction insn) { + if (insn.getArray() != null) { + markAsNotNull(insn.getArray()); + } + } + private void insertNotNullInstruction(Instruction currentInstruction, Variable var) { if (notNullVariables.get(var.getIndex())) { return; diff --git a/core/src/main/java/org/teavm/model/instructions/AbstractInstructionReader.java b/core/src/main/java/org/teavm/model/instructions/AbstractInstructionReader.java index ccf7180f1..942c739ee 100644 --- a/core/src/main/java/org/teavm/model/instructions/AbstractInstructionReader.java +++ b/core/src/main/java/org/teavm/model/instructions/AbstractInstructionReader.java @@ -189,4 +189,8 @@ public class AbstractInstructionReader implements InstructionReader { @Override public void monitorExit(VariableReader objectRef) { } + + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + } } 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 340ebb0e1..966ef01f8 100644 --- a/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java +++ b/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java @@ -165,4 +165,8 @@ public abstract class AbstractInstructionVisitor implements InstructionVisitor { @Override public void visit(MonitorExitInstruction insn) { } + + @Override + public void visit(BoundCheckInstruction insn) { + } } diff --git a/core/src/main/java/org/teavm/model/instructions/BoundCheckInstruction.java b/core/src/main/java/org/teavm/model/instructions/BoundCheckInstruction.java new file mode 100644 index 000000000..20a7417a2 --- /dev/null +++ b/core/src/main/java/org/teavm/model/instructions/BoundCheckInstruction.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019 konsoletyper. + * + * 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.instructions; + +import org.teavm.model.Instruction; +import org.teavm.model.Variable; + +public class BoundCheckInstruction extends Instruction { + private Variable receiver; + private Variable index; + private Variable array; + private boolean lower; + + public Variable getReceiver() { + return receiver; + } + + public void setReceiver(Variable receiver) { + this.receiver = receiver; + } + + public Variable getIndex() { + return index; + } + + public void setIndex(Variable index) { + this.index = index; + } + + public Variable getArray() { + return array; + } + + public void setArray(Variable array) { + this.array = array; + } + + public boolean isLower() { + return lower; + } + + public void setLower(boolean lower) { + this.lower = lower; + } + + @Override + public void acceptVisitor(InstructionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/model/instructions/InstructionReader.java b/core/src/main/java/org/teavm/model/instructions/InstructionReader.java index 1346dee71..8991ef290 100644 --- a/core/src/main/java/org/teavm/model/instructions/InstructionReader.java +++ b/core/src/main/java/org/teavm/model/instructions/InstructionReader.java @@ -103,4 +103,6 @@ public interface InstructionReader { void monitorEnter(VariableReader objectRef); void monitorExit(VariableReader objectRef); + + void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower); } diff --git a/core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java b/core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java index 6b8d27343..c11b41d99 100644 --- a/core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java +++ b/core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java @@ -91,4 +91,6 @@ public interface InstructionVisitor { void visit(MonitorEnterInstruction insn); void visit(MonitorExitInstruction insn); + + void visit(BoundCheckInstruction insn); } 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 e0df0d8d4..159acc620 100644 --- a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java +++ b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java @@ -280,7 +280,6 @@ public class GlobalValueNumbering implements MethodOptimization { insn.setFirstOperand(program.variableAt(p)); insn.setSecondOperand(program.variableAt(q)); boolean commutative = false; - boolean noReplace = false; String value; switch (insn.getOperation()) { case ADD: @@ -302,7 +301,6 @@ public class GlobalValueNumbering implements MethodOptimization { break; case COMPARE: value = "$"; - noReplace = true; break; case AND: value = "&"; 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 3754bb448..1563e8e24 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java @@ -15,49 +15,29 @@ */ package org.teavm.model.optimization; -import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.analysis.NullnessInformation; +import org.teavm.model.instructions.AbstractInstructionVisitor; 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; -public class LoopInvariantAnalyzer implements InstructionVisitor { +public class LoopInvariantAnalyzer extends AbstractInstructionVisitor { private NullnessInformation nullness; public boolean canMove; public boolean constant; @@ -73,10 +53,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor { sideEffect = false; } - @Override - public void visit(EmptyInstruction insn) { - } - @Override public void visit(ClassConstantInstruction insn) { constant = true; @@ -146,50 +122,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor { canMove = true; } - @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) { canMove = true; @@ -198,10 +130,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor { } } - @Override - public void visit(CloneArrayInstruction insn) { - } - @Override public void visit(UnwrapArrayInstruction insn) { canMove = true; @@ -210,31 +138,11 @@ public class LoopInvariantAnalyzer implements InstructionVisitor { } } - @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) { canMove = true; } - @Override - public void visit(InitClassInstruction insn) { - } - @Override public void visit(NullCheckInstruction insn) { canMove = true; @@ -242,12 +150,4 @@ public class LoopInvariantAnalyzer implements InstructionVisitor { sideEffect = true; } } - - @Override - public void visit(MonitorEnterInstruction insn) { - } - - @Override - public void visit(MonitorExitInstruction insn) { - } } diff --git a/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java b/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java index ab813854f..31c1e6582 100644 --- a/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java +++ b/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java @@ -136,7 +136,7 @@ public class ScalarReplacement implements MethodOptimization { private EscapeAnalysis escapeAnalysis; private List> fieldMappings; - public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, + ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, List> fieldMappings) { this.escapeAnalysis = escapeAnalysis; this.fieldMappings = fieldMappings; 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 aa8a7c4f0..d49d792f6 100644 --- a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java @@ -27,6 +27,7 @@ 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; @@ -260,5 +261,10 @@ public class UnusedVariableElimination implements MethodOptimization { public void visit(NullCheckInstruction insn) { requestUsage(insn.getReceiver()); } + + @Override + public void visit(BoundCheckInstruction insn) { + requestUsage(insn.getReceiver()); + } } } diff --git a/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java b/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java index 56d69cbe5..390a93477 100644 --- a/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java +++ b/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java @@ -27,6 +27,7 @@ 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; @@ -61,10 +62,10 @@ public final class VariableUsageGraphBuilder { return builder.build(); } - private static class InstructionAnalyzer extends AbstractInstructionVisitor { + static class InstructionAnalyzer extends AbstractInstructionVisitor { private GraphBuilder builder; - public InstructionAnalyzer(GraphBuilder builder) { + InstructionAnalyzer(GraphBuilder builder) { this.builder = builder; } @@ -150,5 +151,14 @@ public final class VariableUsageGraphBuilder { public void visit(NullCheckInstruction insn) { use(insn.getReceiver(), insn.getValue()); } + + @Override + public void visit(BoundCheckInstruction insn) { + if (insn.getArray() != null) { + use(insn.getReceiver(), insn.getIndex(), insn.getArray()); + } else { + use(insn.getReceiver(), insn.getIndex()); + } + } } } 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 6fbd7598c..18b03691d 100644 --- a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java @@ -544,4 +544,15 @@ class InstructionStringifier implements InstructionReader { public void monitorExit(VariableReader objectRef) { append("monitorExit ").appendLocalVar(objectRef); } + + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + appendLocalVar(receiver).append(" = boundCheck ").appendLocalVar(index); + if (array != null) { + append(" upper ").appendLocalVar(array); + } + if (lower) { + append(" lower"); + } + } } diff --git a/core/src/main/java/org/teavm/model/text/ListingLexer.java b/core/src/main/java/org/teavm/model/text/ListingLexer.java index 9aa1e76d0..d67f7c667 100644 --- a/core/src/main/java/org/teavm/model/text/ListingLexer.java +++ b/core/src/main/java/org/teavm/model/text/ListingLexer.java @@ -26,7 +26,7 @@ class ListingLexer { private int index = -1; private int tokenStart; - public ListingLexer(Reader reader) { + ListingLexer(Reader reader) { this.reader = reader; } @@ -34,6 +34,14 @@ class ListingLexer { return token; } + public boolean tryConsumeIdentifier(String value) throws IOException, ListingParseException { + if (token == ListingToken.IDENTIFIER && value.equals(tokenValue)) { + nextToken(); + return true; + } + return false; + } + public Object getTokenValue() { return tokenValue; } diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index 9a5abef63..73c85d61b 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -43,6 +43,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; @@ -431,6 +432,19 @@ public class ListingParser { currentBlock.setExceptionVariable(receiver); break; } + case "boundCheck": { + lexer.nextToken(); + BoundCheckInstruction insn = new BoundCheckInstruction(); + insn.setReceiver(receiver); + insn.setIndex(expectVariable()); + if (lexer.tryConsumeIdentifier("upper")) { + insn.setArray(expectVariable()); + } + if (lexer.tryConsumeIdentifier("lower")) { + insn.setLower(true); + } + addInstruction(insn); + } default: unexpected(); break; diff --git a/core/src/main/java/org/teavm/model/util/DefinitionExtractor.java b/core/src/main/java/org/teavm/model/util/DefinitionExtractor.java index 84163061a..3203ef485 100644 --- a/core/src/main/java/org/teavm/model/util/DefinitionExtractor.java +++ b/core/src/main/java/org/teavm/model/util/DefinitionExtractor.java @@ -218,4 +218,9 @@ public class DefinitionExtractor implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { definedVariables = new Variable[0]; } + + @Override + public void visit(BoundCheckInstruction insn) { + definedVariables = new Variable[] { insn.getReceiver() }; + } } diff --git a/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java b/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java index 7a3d024a9..0474c3023 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java +++ b/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java @@ -38,6 +38,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; @@ -479,4 +480,17 @@ public class InstructionCopyReader implements InstructionReader { copy = insnCopy; copy.setLocation(location); } + + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + BoundCheckInstruction insnCopy = new BoundCheckInstruction(); + insnCopy.setReceiver(copyVar(receiver)); + insnCopy.setIndex(copyVar(index)); + if (array != null) { + insnCopy.setArray(copyVar(array)); + } + insnCopy.setLower(lower); + copy = insnCopy; + copy.setLocation(location); + } } diff --git a/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java b/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java index 32dad3d31..1fe78670f 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java +++ b/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java @@ -27,6 +27,7 @@ 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.BoundCheckInstruction; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastIntegerInstruction; @@ -304,4 +305,13 @@ public class InstructionVariableMapper extends AbstractInstructionVisitor { public void visit(MonitorExitInstruction insn) { insn.setObjectRef(map(insn.getObjectRef())); } + + @Override + public void visit(BoundCheckInstruction insn) { + insn.setReceiver(map(insn.getReceiver())); + insn.setIndex(map(insn.getIndex())); + if (insn.getArray() != null) { + insn.setArray(map(insn.getArray())); + } + } } 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 ec863fbf5..a9e0b1c01 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -42,10 +42,12 @@ import org.teavm.model.Program; import org.teavm.model.Sigma; import org.teavm.model.TryCatchBlock; 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.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryInstruction; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastIntegerInstruction; @@ -580,11 +582,7 @@ public class PhiUpdater { return mappedVar; } - private InstructionVisitor consumer = new InstructionVisitor() { - @Override - public void visit(EmptyInstruction insn) { - } - + private InstructionVisitor consumer = new AbstractInstructionVisitor() { @Override public void visit(ClassConstantInstruction insn) { insn.setReceiver(define(insn.getReceiver())); @@ -649,11 +647,6 @@ public class PhiUpdater { insn.setFirstOperand(use(insn.getFirstOperand())); insn.setSecondOperand(use(insn.getSecondOperand())); } - - @Override - public void visit(JumpInstruction insn) { - } - @Override public void visit(SwitchInstruction insn) { insn.setCondition(use(insn.getCondition())); @@ -788,10 +781,6 @@ public class PhiUpdater { insn.setReceiver(define(insn.getReceiver())); } - @Override - public void visit(InitClassInstruction insn) { - } - @Override public void visit(NullCheckInstruction insn) { insn.setValue(use(insn.getValue())); @@ -807,6 +796,15 @@ public class PhiUpdater { public void visit(MonitorExitInstruction insn) { insn.setObjectRef(use(insn.getObjectRef())); } + + @Override + public void visit(BoundCheckInstruction insn) { + insn.setIndex(use(insn.getIndex())); + if (insn.getArray() != null) { + insn.setArray(use(insn.getArray())); + } + insn.setReceiver(define(insn.getReceiver())); + } }; } diff --git a/core/src/main/java/org/teavm/model/util/TransitionExtractor.java b/core/src/main/java/org/teavm/model/util/TransitionExtractor.java index 42a49e336..3821bb46a 100644 --- a/core/src/main/java/org/teavm/model/util/TransitionExtractor.java +++ b/core/src/main/java/org/teavm/model/util/TransitionExtractor.java @@ -216,4 +216,9 @@ public class TransitionExtractor implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { targets = null; } + + @Override + public void visit(BoundCheckInstruction insn) { + targets = null; + } } diff --git a/core/src/main/java/org/teavm/model/util/TypeInferer.java b/core/src/main/java/org/teavm/model/util/TypeInferer.java index 257806ff6..747fb4d86 100644 --- a/core/src/main/java/org/teavm/model/util/TypeInferer.java +++ b/core/src/main/java/org/teavm/model/util/TypeInferer.java @@ -322,6 +322,11 @@ public class TypeInferer { public void arrayLength(VariableReader receiver, VariableReader array) { types[receiver.getIndex()] = new InferenceType(InferenceKind.INT, 0); } + + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + types[receiver.getIndex()] = new InferenceType(InferenceKind.INT, 0); + } }; enum InferenceKind { diff --git a/core/src/main/java/org/teavm/model/util/UsageExtractor.java b/core/src/main/java/org/teavm/model/util/UsageExtractor.java index 8029178a5..82eae011e 100644 --- a/core/src/main/java/org/teavm/model/util/UsageExtractor.java +++ b/core/src/main/java/org/teavm/model/util/UsageExtractor.java @@ -225,4 +225,13 @@ public class UsageExtractor implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { usedVariables = new Variable[] {insn.getObjectRef() }; } + + @Override + public void visit(BoundCheckInstruction insn) { + if (insn.getArray() != null) { + usedVariables = new Variable[] { insn.getArray(), insn.getIndex() }; + } else { + usedVariables = new Variable[] { insn.getIndex() }; + } + } } diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java index b3375e9ed..3734704f6 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java @@ -61,6 +61,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.CastInstruction; @@ -1169,5 +1170,17 @@ public class CompositeMethodGenerator { insn.setObjectRef(var(objectRef)); add(insn); } + + @Override + public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) { + BoundCheckInstruction instruction = new BoundCheckInstruction(); + instruction.setReceiver(var(receiver)); + instruction.setIndex(var(index)); + if (array != null) { + instruction.setArray(var(array)); + } + instruction.setLower(lower); + add(instruction); + } } }