Fixes casting between integer values. Fixes naming generation of

methods. Adds more informative exception trace when no method was found
during rendering
This commit is contained in:
Alexey Andreev 2013-12-04 11:46:17 +04:00
parent 59615f3165
commit 3f1a44eccb
24 changed files with 409 additions and 123 deletions

View File

@ -22,7 +22,7 @@ public class SystemTests {
@Test(expected = IndexOutOfBoundsException.class) @Test(expected = IndexOutOfBoundsException.class)
public void failsToCopyArraysWithInvalidIndexes() { public void failsToCopyArraysWithInvalidIndexes() {
System.arraycopy(new Object[0], 0, new TObject[0], 0, 1); System.arraycopy(new Object[0], 0, new Object[0], 0, 1);
} }
@Test(expected = ArrayStoreException.class) @Test(expected = ArrayStoreException.class)
@ -37,6 +37,6 @@ public class SystemTests {
@Test(expected = NullPointerException.class) @Test(expected = NullPointerException.class)
public void failsToCopyToNullTarget() { public void failsToCopyToNullTarget() {
System.arraycopy(new TObject[1], 0, null, 0, 1); System.arraycopy(new Object[1], 0, null, 0, 1);
} }
} }

View File

@ -51,11 +51,12 @@ public class DefaultNamingStrategy implements NamingStrategy {
if (method.getDescriptor().getName().equals("<clinit>")) { if (method.getDescriptor().getName().equals("<clinit>")) {
return "$clinit"; return "$clinit";
} }
method = getRealMethod(method);
if (method == null) {
throw new NamingException("Can't provide name for method as it was not found: " + method);
}
ClassHolder clsHolder = classSource.getClassHolder(method.getClassName()); ClassHolder clsHolder = classSource.getClassHolder(method.getClassName());
MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor()); MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor());
if (methodHolder == null) {
throw new RuntimeException("Method not found: " + method);
}
if (methodHolder.getModifiers().contains(ElementModifier.STATIC) || if (methodHolder.getModifiers().contains(ElementModifier.STATIC) ||
method.getDescriptor().getName().equals("<init>") || method.getDescriptor().getName().equals("<init>") ||
methodHolder.getLevel() == AccessLevel.PRIVATE) { methodHolder.getLevel() == AccessLevel.PRIVATE) {
@ -95,13 +96,32 @@ public class DefaultNamingStrategy implements NamingStrategy {
} }
} }
private MethodReference getRealMethod(MethodReference methodRef) {
String className = methodRef.getClassName();
while (className != null) {
ClassHolder cls = classSource.getClassHolder(className);
if (cls == null) {
return null;
}
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
if (method != null) {
if (method.getLevel() == AccessLevel.PRIVATE && !className.equals(methodRef.getClassName())) {
return null;
}
return new MethodReference(className, method.getDescriptor());
}
className = cls.getParent();
}
return null;
}
private String getRealFieldOwner(String cls, String field) { private String getRealFieldOwner(String cls, String field) {
String initialCls = cls; String initialCls = cls;
while (!fieldExists(cls, field)) { while (!fieldExists(cls, field)) {
ClassHolder clsHolder = classSource.getClassHolder(cls); ClassHolder clsHolder = classSource.getClassHolder(cls);
cls = clsHolder.getParent(); cls = clsHolder.getParent();
if (cls == null) { if (cls == null) {
throw new IllegalArgumentException("Field not found: " + throw new NamingException("Can't provide name for field as the field not found: " +
initialCls + "." + field); initialCls + "." + field);
} }
} }

View File

@ -0,0 +1,17 @@
package org.teavm.codegen;
/**
*
* @author Alexey Andreev
*/
public class NamingException extends RuntimeException {
private static final long serialVersionUID = 3472322553091962348L;
public NamingException() {
super();
}
public NamingException(String message) {
super(message);
}
}

View File

@ -23,9 +23,9 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface NamingStrategy { public interface NamingStrategy {
String getNameFor(String cls); String getNameFor(String cls) throws NamingException;
String getNameFor(MethodReference method); String getNameFor(MethodReference method) throws NamingException;
String getNameFor(FieldReference field); String getNameFor(FieldReference field) throws NamingException;
} }

View File

@ -45,19 +45,19 @@ public class SourceWriter {
return this; return this;
} }
public SourceWriter appendClass(String cls) { public SourceWriter appendClass(String cls) throws NamingException {
appendIndent(); appendIndent();
sb.append(naming.getNameFor(cls)); sb.append(naming.getNameFor(cls));
return this; return this;
} }
public SourceWriter appendField(FieldReference field) { public SourceWriter appendField(FieldReference field) throws NamingException {
appendIndent(); appendIndent();
sb.append(naming.getNameFor(field)); sb.append(naming.getNameFor(field));
return this; return this;
} }
public SourceWriter appendMethod(MethodReference method) { public SourceWriter appendMethod(MethodReference method) throws NamingException {
appendIndent(); appendIndent();
sb.append(naming.getNameFor(method)); sb.append(naming.getNameFor(method));
return this; return this;

View File

@ -270,6 +270,10 @@ class DependencyGraphBuilder {
valueNode.connect(receiverNode); valueNode.connect(receiverNode);
} }
@Override
public void visit(CastIntegerInstruction insn) {
}
@Override @Override
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
DependencyNode valueNode = nodes[insn.getAssignee().getIndex()]; DependencyNode valueNode = nodes[insn.getAssignee().getIndex()];

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.javascript; package org.teavm.javascript;
import org.teavm.codegen.NamingException;
import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter; import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ast.*; import org.teavm.javascript.ast.*;
@ -45,10 +46,14 @@ public class Renderer implements ExprVisitor, StatementVisitor {
return naming; return naming;
} }
public void renderRuntime() { public void renderRuntime() throws RenderingException {
renderRuntimeCls(); try {
renderRuntimeString(); renderRuntimeCls();
renderRuntimeObjcls(); renderRuntimeString();
renderRuntimeObjcls();
} catch (NamingException e) {
throw new RenderingException("Error rendering runtime methods. See a cause for details", e);
}
} }
private void renderRuntimeCls() { private void renderRuntimeCls() {
@ -87,7 +92,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append("var characters = $rt_createNumericArray($rt_charcls(), str.length);").newLine(); writer.append("var characters = $rt_createNumericArray($rt_charcls(), str.length);").newLine();
writer.append("var charsBuffer = characters.data;").newLine(); writer.append("var charsBuffer = characters.data;").newLine();
writer.append("for (var i = 0; i < str.length; i = (i + 1) | 0) {").indent().newLine(); writer.append("for (var i = 0; i < str.length; i = (i + 1) | 0) {").indent().newLine();
writer.append("charsBuffer[i] = str.charCodeAt(i);").newLine(); writer.append("charsBuffer[i] = str.charCodeAt(i) & 0xFFFF;").newLine();
writer.outdent().append("}").newLine(); writer.outdent().append("}").newLine();
writer.append("return ").appendClass("java.lang.String").append(".") writer.append("return ").appendClass("java.lang.String").append(".")
.appendMethod(stringCons).append("(characters);").newLine(); .appendMethod(stringCons).append("(characters);").newLine();
@ -98,58 +103,62 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append("$rt_objcls = function() { return ").appendClass("java.lang.Object").append("; }").newLine(); writer.append("$rt_objcls = function() { return ").appendClass("java.lang.Object").append("; }").newLine();
} }
public void render(ClassNode cls) { public void render(ClassNode cls) throws RenderingException {
writer.appendClass(cls.getName()).append(" = function() {").indent().newLine(); try {
for (FieldNode field : cls.getFields()) { writer.appendClass(cls.getName()).append(" = function() {").indent().newLine();
if (field.getModifiers().contains(NodeModifier.STATIC)) { for (FieldNode field : cls.getFields()) {
continue; if (field.getModifiers().contains(NodeModifier.STATIC)) {
continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.append("this.").appendField(new FieldReference(cls.getName(), field.getName())).append(" = ")
.append(constantToString(value)).append(";").newLine();
} }
Object value = field.getInitialValue(); writer.append("this.$class = ").appendClass(cls.getName()).append(";").newLine();
if (value == null) { writer.outdent().append("}").newLine();
value = getDefaultValue(field.getType());
}
writer.append("this.").appendField(new FieldReference(cls.getName(), field.getName())).append(" = ")
.append(constantToString(value)).append(";").newLine();
}
writer.append("this.$class = ").appendClass(cls.getName()).append(";").newLine();
writer.outdent().append("}").newLine();
for (FieldNode field : cls.getFields()) { for (FieldNode field : cls.getFields()) {
if (!field.getModifiers().contains(NodeModifier.STATIC)) { if (!field.getModifiers().contains(NodeModifier.STATIC)) {
continue; continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.appendClass(cls.getName()).append('.')
.appendField(new FieldReference(cls.getName(), field.getName())).append(" = ")
.append(constantToString(value)).append(";").newLine();
} }
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.appendClass(cls.getName()).append('.')
.appendField(new FieldReference(cls.getName(), field.getName())).append(" = ")
.append(constantToString(value)).append(";").newLine();
}
writer.appendClass(cls.getName()).append(".prototype = new ") writer.appendClass(cls.getName()).append(".prototype = new ")
.append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) : .append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) :
"Object").append("();").newLine(); "Object").append("();").newLine();
writer.appendClass(cls.getName()).append(".$meta = { "); writer.appendClass(cls.getName()).append(".$meta = { ");
writer.append("name : \"").append(cls.getName()).append("\", "); writer.append("name : \"").append(cls.getName()).append("\", ");
writer.append("primitive : false, "); writer.append("primitive : false, ");
writer.append("supertypes : ["); writer.append("supertypes : [");
boolean first = true; boolean first = true;
if (cls.getParentName() != null) { if (cls.getParentName() != null) {
writer.appendClass(cls.getParentName()); writer.appendClass(cls.getParentName());
first = false; first = false;
}
for (String iface : cls.getInterfaces()) {
if (!first) {
writer.append(", ");
} }
first = false; for (String iface : cls.getInterfaces()) {
writer.appendClass(iface); if (!first) {
} writer.append(", ");
writer.append("]"); }
writer.append(" };").newLine(); first = false;
for (MethodNode method : cls.getMethods()) { writer.appendClass(iface);
render(method); }
writer.append("]");
writer.append(" };").newLine();
for (MethodNode method : cls.getMethods()) {
render(method);
}
} catch (NamingException e) {
throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e);
} }
} }
@ -201,40 +210,45 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.outdent().append("}").newLine(); writer.outdent().append("}").newLine();
} }
public void render(MethodNode method) { public void render(MethodNode method) throws RenderingException {
MethodReference ref = method.getReference(); try {
if (ref.getDescriptor().getName().equals("<init>")) { MethodReference ref = method.getReference();
renderInitializer(method); if (ref.getDescriptor().getName().equals("<init>")) {
} renderInitializer(method);
renderWorkingMethod(method);
int startParam = 0;
if (method.getModifiers().contains(NodeModifier.STATIC)) {
startParam = 1;
}
writer.appendClass(ref.getClassName()).append('.');
if (startParam == 0) {
writer.append("prototype.");
}
writer.appendMethod(ref).append(" = function(");
for (int i = 1; i <= ref.parameterCount(); ++i) {
if (i > 1) {
writer.append(", ");
} }
writer.append(variableName(i)); renderWorkingMethod(method);
} int startParam = 0;
writer.append(") {").newLine().indent(); if (method.getModifiers().contains(NodeModifier.STATIC)) {
writer.append("return ").appendClass(ref.getClassName()).append('_').appendMethod(ref).append("("); startParam = 1;
if (startParam == 0) {
writer.append("this");
}
for (int i = 1; i <= ref.parameterCount(); ++i) {
if (i > 1 || startParam == 0) {
writer.append(", ");
} }
writer.append(variableName(i)); writer.appendClass(ref.getClassName()).append('.');
if (startParam == 0) {
writer.append("prototype.");
}
writer.appendMethod(ref).append(" = function(");
for (int i = 1; i <= ref.parameterCount(); ++i) {
if (i > 1) {
writer.append(", ");
}
writer.append(variableName(i));
}
writer.append(") {").newLine().indent();
writer.append("return ").appendClass(ref.getClassName()).append('_').appendMethod(ref).append("(");
if (startParam == 0) {
writer.append("this");
}
for (int i = 1; i <= ref.parameterCount(); ++i) {
if (i > 1 || startParam == 0) {
writer.append(", ");
}
writer.append(variableName(i));
}
writer.append(");").newLine();
writer.outdent().append("}").newLine();
} catch (NamingException e) {
throw new RenderingException("Error rendering method " + method.getReference() + ". " +
"See cause for details", e);
} }
writer.append(");").newLine();
writer.outdent().append("}").newLine();
} }
private void renderWorkingMethod(MethodNode method) { private void renderWorkingMethod(MethodNode method) {
@ -599,6 +613,16 @@ public class Renderer implements ExprVisitor, StatementVisitor {
expr.getOperand().acceptVisitor(this); expr.getOperand().acceptVisitor(this);
writer.append(')'); writer.append(')');
break; break;
case BYTE_TO_INT:
writer.append("$rt_byteToInt(");
expr.getOperand().acceptVisitor(this);
writer.append(')');
break;
case SHORT_TO_INT:
writer.append("$rt_shortToInt(");
expr.getOperand().acceptVisitor(this);
writer.append(')');
break;
} }
} }

View File

@ -0,0 +1,25 @@
package org.teavm.javascript;
/**
*
* @author Alexey Andreev
*/
public class RenderingException extends RuntimeException {
private static final long serialVersionUID = 631804556597569547L;
public RenderingException() {
super();
}
public RenderingException(String message, Throwable cause) {
super(message, cause);
}
public RenderingException(String message) {
super(message);
}
public RenderingException(Throwable cause) {
super(cause);
}
}

View File

@ -274,6 +274,37 @@ public class StatementGenerator implements InstructionVisitor {
assign(value, insn.getReceiver().getIndex()); assign(value, insn.getReceiver().getIndex());
} }
@Override
public void visit(CastIntegerInstruction insn) {
Expr value = Expr.var(insn.getValue().getIndex());
switch (insn.getDirection()) {
case FROM_INTEGER:
switch (insn.getTargetType()) {
case BYTE:
value = Expr.binary(BinaryOperation.BITWISE_AND, value, Expr.constant(0xFF));
break;
case SHORT:
case CHARACTER:
value = Expr.binary(BinaryOperation.BITWISE_AND, value, Expr.constant(0xFFFF));
break;
}
break;
case TO_INTEGER:
switch (insn.getTargetType()) {
case BYTE:
value = Expr.unary(UnaryOperation.BYTE_TO_INT, value);
break;
case SHORT:
value = Expr.unary(UnaryOperation.SHORT_TO_INT, value);
break;
case CHARACTER:
break;
}
break;
}
assign(value, insn.getReceiver().getIndex());
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
switch (insn.getCondition()) { switch (insn.getCondition()) {

View File

@ -27,5 +27,7 @@ public enum UnaryOperation {
LENGTH, LENGTH,
LONG_TO_NUM, LONG_TO_NUM,
NUM_TO_LONG, NUM_TO_LONG,
INT_TO_LONG INT_TO_LONG,
BYTE_TO_INT,
SHORT_TO_INT
} }

View File

@ -0,0 +1,10 @@
package org.teavm.model.instructions;
/**
*
* @author Alexey Andreev
*/
public enum CastIntegerDirection {
FROM_INTEGER,
TO_INTEGER
}

View File

@ -0,0 +1,49 @@
package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev
*/
public class CastIntegerInstruction extends Instruction {
private Variable value;
private Variable receiver;
private IntegerSubtype targetType;
private CastIntegerDirection direction;
public CastIntegerInstruction(IntegerSubtype targetType, CastIntegerDirection direction) {
this.targetType = targetType;
this.direction = direction;
}
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;
}
public IntegerSubtype getTargetType() {
return targetType;
}
public CastIntegerDirection getDirection() {
return direction;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -31,6 +31,8 @@ public interface InstructionVisitor {
void visit(CastNumberInstruction insn); void visit(CastNumberInstruction insn);
void visit(CastIntegerInstruction insn);
void visit(BranchingInstruction insn); void visit(BranchingInstruction insn);
void visit(BinaryBranchingInstruction insn); void visit(BinaryBranchingInstruction insn);

View File

@ -0,0 +1,11 @@
package org.teavm.model.instructions;
/**
*
* @author Alexey Andreev
*/
public enum IntegerSubtype {
BYTE,
SHORT,
CHARACTER
}

View File

@ -156,6 +156,10 @@ class ClassRefsRenamer implements InstructionVisitor {
public void visit(CastNumberInstruction insn) { public void visit(CastNumberInstruction insn) {
} }
@Override
public void visit(CastIntegerInstruction insn) {
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
} }

View File

@ -163,6 +163,11 @@ public class DefinitionExtractor implements InstructionVisitor {
definedVariables = new Variable[] { insn.getReceiver() }; definedVariables = new Variable[] { insn.getReceiver() };
} }
@Override
public void visit(CastIntegerInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() };
}
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() }; definedVariables = new Variable[] { insn.getReceiver() };

View File

@ -307,6 +307,13 @@ public class InstructionStringifier implements InstructionVisitor {
.append(" to ").append(insn.getTargetType()); .append(" to ").append(insn.getTargetType());
} }
@Override
public void visit(CastIntegerInstruction insn) {
sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @")
.append(insn.getValue().getIndex())
.append(" from INT to ").append(insn.getTargetType());
}
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
sb.append("@").append(insn.getReceiver().getIndex()).append("@").append(" := @") sb.append("@").append(insn.getReceiver().getIndex()).append("@").append(" := @")

View File

@ -160,6 +160,11 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
targets = null; targets = null;
} }
@Override
public void visit(CastIntegerInstruction insn) {
targets = null;
}
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
targets = null; targets = null;

View File

@ -137,6 +137,11 @@ public class UnusedVariableElimination implements MethodOptimization {
requestUsage(insn.getReceiver()); requestUsage(insn.getReceiver());
} }
@Override
public void visit(CastIntegerInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
} }

View File

@ -82,6 +82,10 @@ public class VariableEscapeAnalyzer {
public void visit(CastNumberInstruction insn) { public void visit(CastNumberInstruction insn) {
} }
@Override
public void visit(CastIntegerInstruction insn) {
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
escaping[insn.getOperand().getIndex()] = true; escaping[insn.getOperand().getIndex()] = true;

View File

@ -97,6 +97,11 @@ public class VariableUsageGraphBuilder {
use(insn.getReceiver(), insn.getValue()); use(insn.getReceiver(), insn.getValue());
} }
@Override
public void visit(CastIntegerInstruction insn) {
use(insn.getReceiver(), insn.getValue());
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
} }

View File

@ -39,6 +39,7 @@ public class ProgramParser {
private List<List<Instruction>> targetInstructions; private List<List<Instruction>> targetInstructions;
private List<Instruction> builder = new ArrayList<>(); private List<Instruction> builder = new ArrayList<>();
private List<BasicBlock> basicBlocks = new ArrayList<>(); private List<BasicBlock> basicBlocks = new ArrayList<>();
private int[] localsMap;
private int minLocal; private int minLocal;
private Program program; private Program program;
@ -71,13 +72,18 @@ public class ProgramParser {
if ((method.access & Opcodes.ACC_STATIC) == 0) { if ((method.access & Opcodes.ACC_STATIC) == 0) {
getVariable(var++); getVariable(var++);
} }
ValueType[] desc = MethodDescriptor.parseSignature(method.desc); ValueType[] desc = MethodDescriptor.parse(method.desc).getParameterTypes();
for (ValueType paramType : desc) { int mappedLocal = 0;
localsMap = new int[desc.length * 2];
for (int i = 0; i < desc.length; ++i) {
ValueType paramType = desc[i];
localsMap[mappedLocal++] = i;
getVariable(var++); getVariable(var++);
if (paramType instanceof ValueType.Primitive) { if (paramType instanceof ValueType.Primitive) {
switch (((ValueType.Primitive)paramType).getKind()) { switch (((ValueType.Primitive)paramType).getKind()) {
case LONG: case LONG:
case DOUBLE: case DOUBLE:
localsMap[mappedLocal++] = i;
getVariable(var++); getVariable(var++);
break; break;
default: default:
@ -85,6 +91,7 @@ public class ProgramParser {
} }
} }
} }
localsMap = Arrays.copyOf(localsMap, mappedLocal);
} }
private void prepare(MethodNode method) { private void prepare(MethodNode method) {
@ -199,6 +206,13 @@ public class ProgramParser {
builder.add(insn); builder.add(insn);
} }
private int mapLocal(int local) {
if (local < localsMap.length) {
local = localsMap[local];
}
return local;
}
private MethodVisitor methodVisitor = new MethodVisitor() { private MethodVisitor methodVisitor = new MethodVisitor() {
@Override @Override
public void visitVarInsn(int opcode, int local) { public void visitVarInsn(int opcode, int local) {
@ -206,24 +220,24 @@ public class ProgramParser {
case Opcodes.ILOAD: case Opcodes.ILOAD:
case Opcodes.FLOAD: case Opcodes.FLOAD:
case Opcodes.ALOAD: case Opcodes.ALOAD:
emitAssignInsn(minLocal + local, currentDepth); emitAssignInsn(minLocal + mapLocal(local), currentDepth);
currentDepth++; currentDepth++;
break; break;
case Opcodes.LLOAD: case Opcodes.LLOAD:
case Opcodes.DLOAD: case Opcodes.DLOAD:
emitAssignInsn(minLocal + local, currentDepth); emitAssignInsn(minLocal + mapLocal(local), currentDepth);
currentDepth += 2; currentDepth += 2;
break; break;
case Opcodes.ISTORE: case Opcodes.ISTORE:
case Opcodes.FSTORE: case Opcodes.FSTORE:
case Opcodes.ASTORE: case Opcodes.ASTORE:
currentDepth--; currentDepth--;
emitAssignInsn(currentDepth, minLocal + local); emitAssignInsn(currentDepth, minLocal + mapLocal(local));
break; break;
case Opcodes.LSTORE: case Opcodes.LSTORE:
case Opcodes.DSTORE: case Opcodes.DSTORE:
currentDepth -= 2; currentDepth -= 2;
emitAssignInsn(currentDepth, minLocal + local); emitAssignInsn(currentDepth, minLocal + mapLocal(local));
break; break;
} }
} }
@ -499,11 +513,10 @@ public class ProgramParser {
builder.add(insn); builder.add(insn);
} }
private void emitCast(ValueType targetType, int value, int result) { private void emitNumberCast(NumericOperandType source, NumericOperandType target, int value, int result) {
CastInstruction insn = new CastInstruction(); CastNumberInstruction insn = new CastNumberInstruction(source, target);
insn.setReceiver(getVariable(result)); insn.setReceiver(getVariable(result));
insn.setValue(getVariable(value)); insn.setValue(getVariable(value));
insn.setTargetType(targetType);
builder.add(insn); builder.add(insn);
} }
@ -783,21 +796,39 @@ public class ProgramParser {
case Opcodes.FCONST_2: case Opcodes.FCONST_2:
pushConstant(2F); pushConstant(2F);
break; break;
case Opcodes.BALOAD: case Opcodes.BALOAD: {
loadArrayElement(1, ArrayElementType.BYTE); loadArrayElement(1, ArrayElementType.BYTE);
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.BYTE,
CastIntegerDirection.TO_INTEGER);
insn.setValue(getVariable(currentDepth));
insn.setReceiver(getVariable(currentDepth));
builder.add(insn);
break; break;
}
case Opcodes.IALOAD: case Opcodes.IALOAD:
loadArrayElement(1, ArrayElementType.INT); loadArrayElement(1, ArrayElementType.INT);
break; break;
case Opcodes.FALOAD: case Opcodes.FALOAD:
loadArrayElement(1, ArrayElementType.FLOAT); loadArrayElement(1, ArrayElementType.FLOAT);
break; break;
case Opcodes.SALOAD: case Opcodes.SALOAD: {
loadArrayElement(1, ArrayElementType.SHORT); loadArrayElement(1, ArrayElementType.SHORT);
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.SHORT,
CastIntegerDirection.TO_INTEGER);
insn.setValue(getVariable(currentDepth));
insn.setReceiver(getVariable(currentDepth));
builder.add(insn);
break; break;
case Opcodes.CALOAD: }
case Opcodes.CALOAD: {
loadArrayElement(1, ArrayElementType.CHAR); loadArrayElement(1, ArrayElementType.CHAR);
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHARACTER,
CastIntegerDirection.TO_INTEGER);
insn.setValue(getVariable(currentDepth));
insn.setReceiver(getVariable(currentDepth));
builder.add(insn);
break; break;
}
case Opcodes.AALOAD: case Opcodes.AALOAD:
loadArrayElement(1, ArrayElementType.OBJECT); loadArrayElement(1, ArrayElementType.OBJECT);
break; break;
@ -1169,85 +1200,97 @@ public class ProgramParser {
} }
case Opcodes.I2B: { case Opcodes.I2B: {
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.BYTE, val, val); CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.BYTE,
CastIntegerDirection.FROM_INTEGER);
insn.setValue(getVariable(val));
insn.setReceiver(getVariable(val));
builder.add(insn);
break; break;
} }
case Opcodes.I2C: { case Opcodes.I2C: {
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.CHARACTER, val, val); CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHARACTER,
CastIntegerDirection.FROM_INTEGER);
insn.setValue(getVariable(val));
insn.setReceiver(getVariable(val));
builder.add(insn);
break; break;
} }
case Opcodes.I2S: { case Opcodes.I2S: {
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.SHORT, val, val); CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.SHORT,
CastIntegerDirection.FROM_INTEGER);
insn.setValue(getVariable(val));
insn.setReceiver(getVariable(val));
builder.add(insn);
break; break;
} }
case Opcodes.I2F: { case Opcodes.I2F: {
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.FLOAT, val, val); emitNumberCast(NumericOperandType.INT, NumericOperandType.FLOAT, val, val);
break; break;
} }
case Opcodes.I2L: { case Opcodes.I2L: {
int val = currentDepth - 1; int val = currentDepth - 1;
++currentDepth; ++currentDepth;
emitCast(ValueType.LONG, val, val); emitNumberCast(NumericOperandType.INT, NumericOperandType.LONG, val, val);
break; break;
} }
case Opcodes.I2D: { case Opcodes.I2D: {
int val = currentDepth - 1; int val = currentDepth - 1;
++currentDepth; ++currentDepth;
emitCast(ValueType.DOUBLE, val, val); emitNumberCast(NumericOperandType.INT, NumericOperandType.DOUBLE, val, val);
break; break;
} }
case Opcodes.F2I: { case Opcodes.F2I: {
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.INTEGER, val, val); emitNumberCast(NumericOperandType.FLOAT, NumericOperandType.INT, val, val);
break; break;
} }
case Opcodes.F2L: { case Opcodes.F2L: {
int val = currentDepth - 1; int val = currentDepth - 1;
++currentDepth; ++currentDepth;
emitCast(ValueType.LONG, val, val); emitNumberCast(NumericOperandType.FLOAT, NumericOperandType.LONG, val, val);
break; break;
} }
case Opcodes.F2D: { case Opcodes.F2D: {
int val = currentDepth - 1; int val = currentDepth - 1;
++currentDepth; ++currentDepth;
emitCast(ValueType.DOUBLE, val, val); emitNumberCast(NumericOperandType.FLOAT, NumericOperandType.DOUBLE, val, val);
break; break;
} }
case Opcodes.D2L: { case Opcodes.D2L: {
int val = currentDepth - 2; int val = currentDepth - 2;
emitCast(ValueType.LONG, val, val); emitNumberCast(NumericOperandType.DOUBLE, NumericOperandType.LONG, val, val);
break; break;
} }
case Opcodes.D2I: { case Opcodes.D2I: {
--currentDepth; --currentDepth;
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.INTEGER, val, val); emitNumberCast(NumericOperandType.DOUBLE, NumericOperandType.INT, val, val);
break; break;
} }
case Opcodes.D2F: { case Opcodes.D2F: {
--currentDepth; --currentDepth;
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.FLOAT, val, val); emitNumberCast(NumericOperandType.DOUBLE, NumericOperandType.FLOAT, val, val);
break; break;
} }
case Opcodes.L2I: { case Opcodes.L2I: {
--currentDepth; --currentDepth;
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.INTEGER, val, val); emitNumberCast(NumericOperandType.LONG, NumericOperandType.INT, val, val);
break; break;
} }
case Opcodes.L2F: { case Opcodes.L2F: {
--currentDepth; --currentDepth;
int val = currentDepth - 1; int val = currentDepth - 1;
emitCast(ValueType.FLOAT, val, val); emitNumberCast(NumericOperandType.LONG, NumericOperandType.FLOAT, val, val);
break; break;
} }
case Opcodes.L2D: { case Opcodes.L2D: {
int val = currentDepth - 2; int val = currentDepth - 2;
emitCast(ValueType.DOUBLE, val, val); emitNumberCast(NumericOperandType.LONG, NumericOperandType.DOUBLE, val, val);
break; break;
} }
case Opcodes.IRETURN: case Opcodes.IRETURN:
@ -1302,6 +1345,7 @@ public class ProgramParser {
@Override @Override
public void visitIincInsn(int var, int increment) { public void visitIincInsn(int var, int increment) {
var = mapLocal(var);
var += minLocal; var += minLocal;
IntegerConstantInstruction intInsn = new IntegerConstantInstruction(); IntegerConstantInstruction intInsn = new IntegerConstantInstruction();
intInsn.setConstant(increment); intInsn.setConstant(increment);

View File

@ -351,6 +351,12 @@ public class SSATransformer {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver()));
} }
@Override
public void visit(CastIntegerInstruction insn) {
insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver()));
}
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));

View File

@ -174,6 +174,12 @@ $rt_throw = function(ex) {
err.$javaException = ex; err.$javaException = ex;
throw err; throw err;
} }
$rt_byteToInt = function(value) {
return value > 0xFF ? value | 0xFFFFFF00 : value;
}
$rt_shortToInt = function(value) {
return value > 0xFFFF ? value | 0xFFFF0000 : value;
}
$rt = { $rt = {
createBooleanArray : function(cls, sz) { createBooleanArray : function(cls, sz) {