Add instruction to perform array bound check

This commit is contained in:
Alexey Andreev 2019-10-02 18:40:45 +03:00
parent 80fb6c1f81
commit a1d7153cab
40 changed files with 434 additions and 129 deletions

View File

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

View File

@ -45,4 +45,6 @@ public interface ExprVisitor {
void visit(CastExpr expr); void visit(CastExpr expr);
void visit(PrimitiveCastExpr expr); void visit(PrimitiveCastExpr expr);
void visit(BoundCheckExpr expr);
} }

View File

@ -227,4 +227,14 @@ public class RecursiveVisitor implements ExprVisitor, StatementVisitor {
public void visit(MonitorExitStatement statement) { public void visit(MonitorExitStatement statement) {
statement.getObjectRef().acceptVisitor(this); 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);
}
} }

View File

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.ConditionalExpr; import org.teavm.ast.ConditionalExpr;
import org.teavm.ast.ConditionalStatement; import org.teavm.ast.ConditionalStatement;
@ -64,8 +65,8 @@ public final class LocationGraphBuilder {
for (int terminal : visitor.nodes) { for (int terminal : visitor.nodes) {
visitor.terminalNodes.set(terminal); visitor.terminalNodes.set(terminal);
} }
TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph, TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph
visitor.terminalNodes); );
Map<TextLocation, Set<TextLocation>> builder = new LinkedHashMap<>(); Map<TextLocation, Set<TextLocation>> builder = new LinkedHashMap<>();
for (int i = 0; i < graph.size(); ++i) { for (int i = 0; i < graph.size(); ++i) {
@ -91,7 +92,7 @@ public final class LocationGraphBuilder {
return result; return result;
} }
private static TextLocation[][] propagate(TextLocation[] locations, Graph graph, BitSet terminal) { private static TextLocation[][] propagate(TextLocation[] locations, Graph graph) {
List<Set<TextLocation>> result = new ArrayList<>(); List<Set<TextLocation>> result = new ArrayList<>();
boolean[] stop = new boolean[graph.size()]; boolean[] stop = new boolean[graph.size()];
IntDeque queue = new IntArrayDeque(); IntDeque queue = new IntArrayDeque();
@ -338,6 +339,12 @@ public final class LocationGraphBuilder {
nodes = distinct(exit); nodes = distinct(exit);
} }
@Override
public void visit(BoundCheckExpr expr) {
super.visit(expr);
setLocation(expr.getLocation());
}
private void setNode(int node) { private void setNode(int node) {
for (int prevNode : nodes) { for (int prevNode : nodes) {
builder.addEdge(prevNode, node); builder.addEdge(prevNode, node);

View File

@ -24,6 +24,7 @@ import java.util.Map;
import org.teavm.ast.ArrayType; import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryOperation; import org.teavm.ast.BinaryOperation;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.ContinueStatement; import org.teavm.ast.ContinueStatement;
import org.teavm.ast.Expr; 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.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
@ -631,4 +633,16 @@ class StatementGenerator implements InstructionVisitor {
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
statements.add(stmt); 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());
}
} }

View File

@ -27,6 +27,7 @@ import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.BinaryOperation; import org.teavm.ast.BinaryOperation;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr; 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() { private Statement addBarrier() {
SequentialStatement barrier = new SequentialStatement(); SequentialStatement barrier = new SequentialStatement();
resultSequence.add(barrier); resultSequence.add(barrier);

View File

@ -100,7 +100,7 @@ class ReadWriteStatsBuilder {
static class ConstantExtractor extends AbstractInstructionVisitor { static class ConstantExtractor extends AbstractInstructionVisitor {
private Object[] constants; private Object[] constants;
public ConstantExtractor(Object[] constants) { ConstantExtractor(Object[] constants) {
this.constants = constants; this.constants = constants;
} }

View File

@ -88,7 +88,6 @@ public class VolatileDefinitionFinder {
private RecursiveVisitor handlerAnalyzer = new RecursiveVisitor() { private RecursiveVisitor handlerAnalyzer = new RecursiveVisitor() {
StackElement surroundingTryCatches; StackElement surroundingTryCatches;
StackElement handlingTryCatches;
@Override @Override
public void visit(TryCatchStatement statement) { public void visit(TryCatchStatement statement) {

View File

@ -41,6 +41,7 @@ import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr; import org.teavm.ast.ConditionalExpr;
@ -1420,6 +1421,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
popLocation(statement.getLocation()); popLocation(statement.getLocation());
} }
@Override
public void visit(BoundCheckExpr expr) {
expr.getIndex().acceptVisitor(this);
}
private IntrinsicContext intrinsicContext = new IntrinsicContext() { private IntrinsicContext intrinsicContext = new IntrinsicContext() {
@Override @Override
public CodeWriter writer() { public CodeWriter writer() {

View File

@ -30,6 +30,7 @@ import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.BinaryOperation; import org.teavm.ast.BinaryOperation;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr; 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 class InjectorContextImpl implements InjectorContext {
private final List<Expr> arguments; private final List<Expr> arguments;
private final Precedence precedence = StatementRenderer.this.precedence; private final Precedence precedence = StatementRenderer.this.precedence;

View File

@ -28,6 +28,7 @@ import java.util.Set;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr; import org.teavm.ast.ConditionalExpr;
@ -1365,6 +1366,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
result = emptyStatement(statement.getLocation()); result = emptyStatement(statement.getLocation());
} }
@Override
public void visit(BoundCheckExpr expr) {
expr.getIndex().acceptVisitor(this);
}
private WasmExpression negate(WasmExpression expr) { private WasmExpression negate(WasmExpression expr) {
if (expr instanceof WasmIntBinary) { if (expr instanceof WasmIntBinary) {
WasmIntBinary binary = (WasmIntBinary) expr; WasmIntBinary binary = (WasmIntBinary) expr;

View File

@ -29,6 +29,7 @@ import org.teavm.ast.AsyncMethodPart;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.BinaryOperation; import org.teavm.ast.BinaryOperation;
import org.teavm.ast.BlockStatement; import org.teavm.ast.BlockStatement;
import org.teavm.ast.BoundCheckExpr;
import org.teavm.ast.BreakStatement; import org.teavm.ast.BreakStatement;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr; import org.teavm.ast.ConditionalExpr;
@ -665,6 +666,19 @@ public class AstIO {
throw new IOExceptionWrapper(e); 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 { private TextLocation readLocation(VarDataInput input) throws IOException {
@ -1024,6 +1038,22 @@ public class AstIO {
expr.setValue(readExpr(input)); expr.setValue(readExpr(input));
return expr; 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: default:
throw new RuntimeException("Unknown expression type: " + type); throw new RuntimeException("Unknown expression type: " + type);
} }

View File

@ -42,7 +42,7 @@ public class ProgramDependencyExtractor extends AbstractInstructionVisitor {
return result; return result;
} }
class AnalyzingVisitor extends AbstractInstructionVisitor { static class AnalyzingVisitor extends AbstractInstructionVisitor {
Set<String> dependencies = new LinkedHashSet<>(); Set<String> dependencies = new LinkedHashSet<>();
@Override public void visit(GetFieldInstruction insn) { @Override public void visit(GetFieldInstruction insn) {
dependencies.add(insn.getField().getClassName()); dependencies.add(insn.getField().getClassName());

View File

@ -48,6 +48,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; 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 { private void write(MethodHandle handle) throws IOException {
switch (handle.getKind()) { switch (handle.getKind()) {
case GET_FIELD: case GET_FIELD:
@ -1205,6 +1220,18 @@ public class ProgramIO {
} }
return insn; 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: default:
throw new RuntimeException("Unknown instruction type: " + insnType); throw new RuntimeException("Unknown instruction type: " + insnType);
} }

View File

@ -35,6 +35,8 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader {
static final MethodReference CLONE_METHOD = new MethodReference(Object.class, "clone", Object.class); static final MethodReference CLONE_METHOD = new MethodReference(Object.class, "clone", Object.class);
private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class, private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class,
"<init>", void.class); "<init>", void.class);
private static final MethodReference AIOOB_INIT_METHOD = new MethodReference(ArrayIndexOutOfBoundsException.class,
"<init>", void.class);
static final MethodReference MONITOR_ENTER_METHOD = new MethodReference(Object.class, static final MethodReference MONITOR_ENTER_METHOD = new MethodReference(Object.class,
"monitorEnter", Object.class, void.class); "monitorEnter", Object.class, void.class);
static final MethodReference MONITOR_ENTER_SYNC_METHOD = new MethodReference(Object.class, static final MethodReference MONITOR_ENTER_SYNC_METHOD = new MethodReference(Object.class,
@ -272,6 +274,14 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader {
methodDep.use(); 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 DependencyNode getNode(VariableReader variable);
protected abstract DependencyAnalyzer getAnalyzer(); protected abstract DependencyAnalyzer getAnalyzer();

View File

@ -213,4 +213,9 @@ public class InstructionReadVisitor implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
reader.monitorExit(insn.getObjectRef()); reader.monitorExit(insn.getObjectRef());
} }
@Override
public void visit(BoundCheckInstruction insn) {
reader.boundCheck(insn.getReceiver(), insn.getIndex(), insn.getArray(), insn.isLower());
}
} }

View File

@ -791,6 +791,11 @@ public class Interpreter {
public void monitorExit(VariableReader objectRef) { 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) { private Class<?> asJvmClass(ValueType type) {
if (type instanceof ValueType.Primitive) { if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) { switch (((ValueType.Primitive) type).getKind()) {

View File

@ -304,7 +304,6 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
static class MethodInfo { static class MethodInfo {
MethodReference method; MethodReference method;
boolean complete; boolean complete;
Set<MethodInfo> recursiveCallers;
Set<String> classesWithModifiedFields; Set<String> classesWithModifiedFields;
boolean anyFieldModified; boolean anyFieldModified;

View File

@ -38,6 +38,7 @@ import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.ClassConstantInstruction; import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.CloneArrayInstruction; import org.teavm.model.instructions.CloneArrayInstruction;
@ -426,6 +427,13 @@ class NullnessInformationBuilder {
markAsNotNull(insn.getReceiver()); markAsNotNull(insn.getReceiver());
} }
@Override
public void visit(BoundCheckInstruction insn) {
if (insn.getArray() != null) {
markAsNotNull(insn.getArray());
}
}
private void insertNotNullInstruction(Instruction currentInstruction, Variable var) { private void insertNotNullInstruction(Instruction currentInstruction, Variable var) {
if (notNullVariables.get(var.getIndex())) { if (notNullVariables.get(var.getIndex())) {
return; return;

View File

@ -189,4 +189,8 @@ public class AbstractInstructionReader implements InstructionReader {
@Override @Override
public void monitorExit(VariableReader objectRef) { public void monitorExit(VariableReader objectRef) {
} }
@Override
public void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower) {
}
} }

View File

@ -165,4 +165,8 @@ public abstract class AbstractInstructionVisitor implements InstructionVisitor {
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
} }
@Override
public void visit(BoundCheckInstruction insn) {
}
} }

View File

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

View File

@ -103,4 +103,6 @@ public interface InstructionReader {
void monitorEnter(VariableReader objectRef); void monitorEnter(VariableReader objectRef);
void monitorExit(VariableReader objectRef); void monitorExit(VariableReader objectRef);
void boundCheck(VariableReader receiver, VariableReader index, VariableReader array, boolean lower);
} }

View File

@ -91,4 +91,6 @@ public interface InstructionVisitor {
void visit(MonitorEnterInstruction insn); void visit(MonitorEnterInstruction insn);
void visit(MonitorExitInstruction insn); void visit(MonitorExitInstruction insn);
void visit(BoundCheckInstruction insn);
} }

View File

@ -280,7 +280,6 @@ public class GlobalValueNumbering implements MethodOptimization {
insn.setFirstOperand(program.variableAt(p)); insn.setFirstOperand(program.variableAt(p));
insn.setSecondOperand(program.variableAt(q)); insn.setSecondOperand(program.variableAt(q));
boolean commutative = false; boolean commutative = false;
boolean noReplace = false;
String value; String value;
switch (insn.getOperation()) { switch (insn.getOperation()) {
case ADD: case ADD:
@ -302,7 +301,6 @@ public class GlobalValueNumbering implements MethodOptimization {
break; break;
case COMPARE: case COMPARE:
value = "$"; value = "$";
noReplace = true;
break; break;
case AND: case AND:
value = "&"; value = "&";

View File

@ -15,49 +15,29 @@
*/ */
package org.teavm.model.optimization; package org.teavm.model.optimization;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.analysis.NullnessInformation; import org.teavm.model.analysis.NullnessInformation;
import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction; import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction; 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.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction; 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.IntegerConstantInstruction;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction; import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction; 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.NegateInstruction;
import org.teavm.model.instructions.NullCheckInstruction; import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.NullConstantInstruction; import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.NumericOperandType; 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.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction; import org.teavm.model.instructions.UnwrapArrayInstruction;
public class LoopInvariantAnalyzer implements InstructionVisitor { public class LoopInvariantAnalyzer extends AbstractInstructionVisitor {
private NullnessInformation nullness; private NullnessInformation nullness;
public boolean canMove; public boolean canMove;
public boolean constant; public boolean constant;
@ -73,10 +53,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
sideEffect = false; sideEffect = false;
} }
@Override
public void visit(EmptyInstruction insn) {
}
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
constant = true; constant = true;
@ -146,50 +122,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
canMove = true; 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 @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
canMove = true; canMove = true;
@ -198,10 +130,6 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
} }
} }
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
canMove = true; 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 @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
canMove = true; canMove = true;
} }
@Override
public void visit(InitClassInstruction insn) {
}
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
canMove = true; canMove = true;
@ -242,12 +150,4 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
sideEffect = true; sideEffect = true;
} }
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -136,7 +136,7 @@ public class ScalarReplacement implements MethodOptimization {
private EscapeAnalysis escapeAnalysis; private EscapeAnalysis escapeAnalysis;
private List<Map<FieldReference, Variable>> fieldMappings; private List<Map<FieldReference, Variable>> fieldMappings;
public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis,
List<Map<FieldReference, Variable>> fieldMappings) { List<Map<FieldReference, Variable>> fieldMappings) {
this.escapeAnalysis = escapeAnalysis; this.escapeAnalysis = escapeAnalysis;
this.fieldMappings = fieldMappings; this.fieldMappings = fieldMappings;

View File

@ -27,6 +27,7 @@ import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction; import org.teavm.model.instructions.CastNumberInstruction;
@ -260,5 +261,10 @@ public class UnusedVariableElimination implements MethodOptimization {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
requestUsage(insn.getReceiver()); requestUsage(insn.getReceiver());
} }
@Override
public void visit(BoundCheckInstruction insn) {
requestUsage(insn.getReceiver());
}
} }
} }

View File

@ -27,6 +27,7 @@ import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction; import org.teavm.model.instructions.CastNumberInstruction;
@ -61,10 +62,10 @@ public final class VariableUsageGraphBuilder {
return builder.build(); return builder.build();
} }
private static class InstructionAnalyzer extends AbstractInstructionVisitor { static class InstructionAnalyzer extends AbstractInstructionVisitor {
private GraphBuilder builder; private GraphBuilder builder;
public InstructionAnalyzer(GraphBuilder builder) { InstructionAnalyzer(GraphBuilder builder) {
this.builder = builder; this.builder = builder;
} }
@ -150,5 +151,14 @@ public final class VariableUsageGraphBuilder {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
use(insn.getReceiver(), insn.getValue()); 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());
}
}
} }
} }

View File

@ -544,4 +544,15 @@ class InstructionStringifier implements InstructionReader {
public void monitorExit(VariableReader objectRef) { public void monitorExit(VariableReader objectRef) {
append("monitorExit ").appendLocalVar(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");
}
}
} }

View File

@ -26,7 +26,7 @@ class ListingLexer {
private int index = -1; private int index = -1;
private int tokenStart; private int tokenStart;
public ListingLexer(Reader reader) { ListingLexer(Reader reader) {
this.reader = reader; this.reader = reader;
} }
@ -34,6 +34,14 @@ class ListingLexer {
return token; 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() { public Object getTokenValue() {
return tokenValue; return tokenValue;
} }

View File

@ -43,6 +43,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
@ -431,6 +432,19 @@ public class ListingParser {
currentBlock.setExceptionVariable(receiver); currentBlock.setExceptionVariable(receiver);
break; 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: default:
unexpected(); unexpected();
break; break;

View File

@ -218,4 +218,9 @@ public class DefinitionExtractor implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
definedVariables = new Variable[0]; definedVariables = new Variable[0];
} }
@Override
public void visit(BoundCheckInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() };
}
} }

View File

@ -38,6 +38,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
@ -479,4 +480,17 @@ public class InstructionCopyReader implements InstructionReader {
copy = insnCopy; copy = insnCopy;
copy.setLocation(location); 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);
}
} }

View File

@ -27,6 +27,7 @@ import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
@ -304,4 +305,13 @@ public class InstructionVariableMapper extends AbstractInstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(map(insn.getObjectRef())); 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()));
}
}
} }

View File

@ -42,10 +42,12 @@ import org.teavm.model.Program;
import org.teavm.model.Sigma; import org.teavm.model.Sigma;
import org.teavm.model.TryCatchBlock; import org.teavm.model.TryCatchBlock;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastIntegerInstruction;
@ -580,11 +582,7 @@ public class PhiUpdater {
return mappedVar; return mappedVar;
} }
private InstructionVisitor consumer = new InstructionVisitor() { private InstructionVisitor consumer = new AbstractInstructionVisitor() {
@Override
public void visit(EmptyInstruction insn) {
}
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver()));
@ -649,11 +647,6 @@ public class PhiUpdater {
insn.setFirstOperand(use(insn.getFirstOperand())); insn.setFirstOperand(use(insn.getFirstOperand()));
insn.setSecondOperand(use(insn.getSecondOperand())); insn.setSecondOperand(use(insn.getSecondOperand()));
} }
@Override
public void visit(JumpInstruction insn) {
}
@Override @Override
public void visit(SwitchInstruction insn) { public void visit(SwitchInstruction insn) {
insn.setCondition(use(insn.getCondition())); insn.setCondition(use(insn.getCondition()));
@ -788,10 +781,6 @@ public class PhiUpdater {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver()));
} }
@Override
public void visit(InitClassInstruction insn) {
}
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
@ -807,6 +796,15 @@ public class PhiUpdater {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(use(insn.getObjectRef())); 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()));
}
}; };
} }

View File

@ -216,4 +216,9 @@ public class TransitionExtractor implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
targets = null; targets = null;
} }
@Override
public void visit(BoundCheckInstruction insn) {
targets = null;
}
} }

View File

@ -322,6 +322,11 @@ public class TypeInferer {
public void arrayLength(VariableReader receiver, VariableReader array) { public void arrayLength(VariableReader receiver, VariableReader array) {
types[receiver.getIndex()] = new InferenceType(InferenceKind.INT, 0); 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 { enum InferenceKind {

View File

@ -225,4 +225,13 @@ public class UsageExtractor implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
usedVariables = new Variable[] {insn.getObjectRef() }; 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() };
}
}
} }

View File

@ -61,6 +61,7 @@ import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction; import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BoundCheckInstruction;
import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
@ -1169,5 +1170,17 @@ public class CompositeMethodGenerator {
insn.setObjectRef(var(objectRef)); insn.setObjectRef(var(objectRef));
add(insn); 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);
}
} }
} }