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(PrimitiveCastExpr expr);
void visit(BoundCheckExpr expr);
}

View File

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

View File

@ -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<TextLocation, Set<TextLocation>> 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<Set<TextLocation>> 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);

View File

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

View File

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

View File

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

View File

@ -88,7 +88,6 @@ public class VolatileDefinitionFinder {
private RecursiveVisitor handlerAnalyzer = new RecursiveVisitor() {
StackElement surroundingTryCatches;
StackElement handlingTryCatches;
@Override
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.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() {

View File

@ -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<Expr> arguments;
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.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;

View File

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

View File

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

View File

@ -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,
"<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,
"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();

View File

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

View File

@ -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()) {

View File

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

View File

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

View File

@ -165,4 +165,8 @@ public abstract class AbstractInstructionVisitor implements InstructionVisitor {
@Override
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 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(MonitorExitInstruction insn);
void visit(BoundCheckInstruction insn);
}

View File

@ -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 = "&";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -216,4 +216,9 @@ public class TransitionExtractor implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) {
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) {
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 {

View File

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

View File

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