Adds NullCheckInstruction

This commit is contained in:
konsoletyper 2014-03-01 19:01:27 +04:00
parent 4c36ab9db1
commit d68f78f77d
22 changed files with 180 additions and 19 deletions

View File

@ -440,5 +440,18 @@ class DependencyGraphBuilder {
}
});
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()];
valueNode.connect(receiverNode);
useRunners.add(new Runnable() {
@Override public void run() {
dependencyChecker.linkMethod(new MethodReference("java.lang.NullPointerException",
"<init>", ValueType.VOID), callerStack);
}
});
}
};
}

View File

@ -18,6 +18,7 @@ package org.teavm.javascript;
import org.teavm.model.*;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.NullCheckInstruction;
/**
*
@ -46,12 +47,12 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer {
if (invoke.getType() != InvocationType.VIRTUAL) {
continue;
}
InvokeInstruction checkInvoke = new InvokeInstruction();
checkInvoke.setMethod(new MethodReference(RuntimeSupport.class.getName(), "requireNonNull",
ValueType.object("java.lang.Object"), ValueType.VOID));
checkInvoke.setType(InvocationType.SPECIAL);
checkInvoke.getArguments().add(invoke.getInstance());
block.getInstructions().add(i++, checkInvoke);
NullCheckInstruction nullCheck = new NullCheckInstruction();
nullCheck.setValue(invoke.getInstance());
Variable var = block.getProgram().createVariable();
nullCheck.setReceiver(var);
invoke.setInstance(var);
block.getInstructions().add(i++, nullCheck);
}
}
}

View File

@ -79,6 +79,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
renderRuntimeString();
renderRuntimeUnwrapString();
renderRuntimeObjcls();
renderRuntimeNullCheck();
} catch (NamingException e) {
throw new RenderingException("Error rendering runtime methods. See a cause for details", e);
} catch (IOException e) {
@ -93,8 +94,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append("var cls").ws().append("=").ws().append("clsProto.classObject;").softNewLine();
writer.append("if").ws().append("(cls").ws().append("===").ws().append("undefined)").ws()
.append("{").softNewLine().indent();
MethodReference createMethodRef = new MethodReference(classClass, new MethodDescriptor("createNew",
ValueType.object(classClass)));
MethodReference createMethodRef = new MethodReference(classClass, "createNew", ValueType.object(classClass));
writer.append("cls").ws().append("=").ws().appendMethodBody(createMethodRef).append("();").softNewLine();
writer.append("cls.$data = clsProto;").softNewLine();
if (classSource.get(classClass).getField("name") != null) {
@ -124,8 +124,8 @@ public class Renderer implements ExprVisitor, StatementVisitor {
private void renderRuntimeString() throws IOException {
String stringClass = "java.lang.String";
MethodReference stringCons = new MethodReference(stringClass, new MethodDescriptor("<init>",
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID));
MethodReference stringCons = new MethodReference(stringClass, "<init>",
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID);
writer.append("$rt_str = function(str) {").indent().softNewLine();
writer.append("var characters = $rt_createCharArray(str.length);").softNewLine();
writer.append("var charsBuffer = characters.data;").softNewLine();
@ -139,16 +139,14 @@ public class Renderer implements ExprVisitor, StatementVisitor {
private void renderRuntimeUnwrapString() throws IOException {
String stringClass = "java.lang.String";
MethodReference stringLen = new MethodReference(stringClass, new MethodDescriptor(
"length", ValueType.INTEGER));
MethodReference getChars = new MethodReference(stringClass, new MethodDescriptor(
"getChars", ValueType.INTEGER, ValueType.INTEGER, ValueType.arrayOf(ValueType.CHARACTER),
ValueType.INTEGER, ValueType.VOID));
MethodReference stringLen = new MethodReference(stringClass, "length", ValueType.INTEGER);
MethodReference getChars = new MethodReference(stringClass, "getChars", ValueType.INTEGER, ValueType.INTEGER,
ValueType.arrayOf(ValueType.CHARACTER), ValueType.INTEGER, ValueType.VOID);
writer.append("$rt_ustr = function(str) {").indent().softNewLine();
writer.append("var result = \"\";").softNewLine();
writer.append("var sz = ").appendMethodBody(stringLen).append("(str);").softNewLine();
writer.append("var array = $rt_createCharArray(sz);");
writer.appendMethodBody(getChars).append("(str, 0, sz, array, 0);");
writer.append("var array = $rt_createCharArray(sz);").softNewLine();
writer.appendMethodBody(getChars).append("(str, 0, sz, array, 0);").softNewLine();
writer.append("for (var i = 0; i < sz; i = (i + 1) | 0) {").indent().softNewLine();
writer.append("result += String.fromCharCode(array.data[i]);").softNewLine();
writer.outdent().append("}").softNewLine();
@ -156,6 +154,17 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.outdent().append("}").newLine();
}
private void renderRuntimeNullCheck() throws IOException {
String npe = "java.lang.NullPointerException";
writer.append("$rt_nullCheck = function(val) {").indent().softNewLine();
writer.append("if (val === null) {").indent().softNewLine();
writer.append("$rt_throw(").appendClass(npe).append('.').appendMethod(npe, "<init>", ValueType.VOID)
.append("());").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return val;").softNewLine();
writer.outdent().append("}").newLine();
}
private void renderRuntimeObjcls() throws IOException {
writer.append("$rt_objcls = function() { return ").appendClass("java.lang.Object").append("; }").newLine();
}
@ -217,7 +226,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
.append("function()").ws().append("{").ws()
.appendClass(cls.getName()).append("_$clinit();").ws().append("}");
}
writer.ws().append("});").softNewLine().outdent();
writer.ws().append("});").newLine().outdent();
List<MethodNode> nonInitMethods = new ArrayList<>();
if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) {
writer.append("function ").appendClass(cls.getName()).append("_$clinit()").ws()
@ -860,6 +869,11 @@ public class Renderer implements ExprVisitor, StatementVisitor {
expr.getOperand().acceptVisitor(this);
writer.append(')');
break;
case NULL_CHECK:
writer.append("$rt_nullCheck(");
expr.getOperand().acceptVisitor(this);
writer.append(')');
break;
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);

View File

@ -613,4 +613,10 @@ class StatementGenerator implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
statements.add(Statement.initClass(insn.getClassName()));
}
@Override
public void visit(NullCheckInstruction insn) {
assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())),
insn.getReceiver().getIndex());
}
}

View File

@ -29,5 +29,6 @@ public enum UnaryOperation {
NUM_TO_LONG,
INT_TO_LONG,
BYTE_TO_INT,
SHORT_TO_INT
SHORT_TO_INT,
NULL_CHECK
}

View File

@ -196,4 +196,9 @@ class InstructionReadVisitor implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
reader.initClass(insn.getClassName());
}
@Override
public void visit(NullCheckInstruction insn) {
reader.nullCheck(insn.getReceiver(), insn.getValue());
}
}

View File

@ -96,4 +96,6 @@ public interface InstructionReader {
void isInstance(VariableReader receiver, VariableReader value, ValueType type);
void initClass(String className);
void nullCheck(VariableReader receiver, VariableReader value);
}

View File

@ -85,4 +85,6 @@ public interface InstructionVisitor {
void visit(IsInstanceInstruction insn);
void visit(InitClassInstruction insn);
void visit(NullCheckInstruction insn);
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class NullCheckInstruction extends Instruction {
private Variable value;
private Variable receiver;
public Variable getValue() {
return value;
}
public void setValue(Variable value) {
this.value = value;
}
public Variable getReceiver() {
return receiver;
}
public void setReceiver(Variable receiver) {
this.receiver = receiver;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -180,4 +180,8 @@ public abstract class BasicBlockMapper implements InstructionVisitor {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
}
}

View File

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

View File

@ -337,4 +337,9 @@ public class InstructionStringifier implements InstructionReader {
public void initClass(String className) {
sb.append("initclass ").append(className);
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
sb.append("@").append(receiver.getIndex()).append(" := nullCheck @").append(value.getIndex());
}
}

View File

@ -199,4 +199,9 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
targets = null;
}
@Override
public void visit(NullCheckInstruction insn) {
targets = null;
}
}

View File

@ -223,4 +223,9 @@ public abstract class InstructionVariableMapper implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue()));
}
}

View File

@ -396,5 +396,13 @@ public class ProgramUtils {
insnCopy.setClassName(insn.getClassName());
copy = insnCopy;
}
@Override
public void visit(NullCheckInstruction insn) {
NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(insn.getReceiver()));
insnCopy.setValue(copyVar(insn.getValue()));
copy = insnCopy;
}
}
}

View File

@ -201,4 +201,9 @@ public class UsageExtractor implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
usedVariables = new Variable[0];
}
@Override
public void visit(NullCheckInstruction insn) {
usedVariables = new Variable[] { insn.getValue() };
}
}

View File

@ -406,5 +406,12 @@ public class CommonSubexpressionElimination implements MethodOptimization {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
int val = map[insn.getValue().getIndex()];
insn.setValue(program.variableAt(val));
bind(insn.getReceiver().getIndex(), "nullCheck @" + val);
}
};
}

View File

@ -243,5 +243,10 @@ public class UnusedVariableElimination implements MethodOptimization {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
requestUsage(insn.getReceiver());
}
}
}

View File

@ -197,5 +197,9 @@ public class VariableEscapeAnalyzer {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
}
}
}

View File

@ -202,5 +202,10 @@ public class VariableUsageGraphBuilder {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
use(insn.getReceiver(), insn.getValue());
}
}
}

View File

@ -277,4 +277,8 @@ class ClassRefsRenamer implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
insn.setClassName(classNameMapper.map(insn.getClassName()));
}
@Override
public void visit(NullCheckInstruction insn) {
}
}

View File

@ -424,5 +424,11 @@ public class SSATransformer {
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver()));
}
};
}