mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Adds NullCheckInstruction
This commit is contained in:
parent
4c36ab9db1
commit
d68f78f77d
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,5 +29,6 @@ public enum UnaryOperation {
|
|||
NUM_TO_LONG,
|
||||
INT_TO_LONG,
|
||||
BYTE_TO_INT,
|
||||
SHORT_TO_INT
|
||||
SHORT_TO_INT,
|
||||
NULL_CHECK
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -85,4 +85,6 @@ public interface InstructionVisitor {
|
|||
void visit(IsInstanceInstruction insn);
|
||||
|
||||
void visit(InitClassInstruction insn);
|
||||
|
||||
void visit(NullCheckInstruction insn);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -180,4 +180,8 @@ public abstract class BasicBlockMapper implements InstructionVisitor {
|
|||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,4 +199,9 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
|
|||
public void visit(InitClassInstruction insn) {
|
||||
targets = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
targets = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -243,5 +243,10 @@ public class UnusedVariableElimination implements MethodOptimization {
|
|||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
requestUsage(insn.getReceiver());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,5 +197,9 @@ public class VariableEscapeAnalyzer {
|
|||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,5 +202,10 @@ public class VariableUsageGraphBuilder {
|
|||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
use(insn.getReceiver(), insn.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user