mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
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:
parent
59615f3165
commit
3f1a44eccb
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.teavm.model.instructions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public enum CastIntegerDirection {
|
||||||
|
FROM_INTEGER,
|
||||||
|
TO_INTEGER
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.teavm.model.instructions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public enum IntegerSubtype {
|
||||||
|
BYTE,
|
||||||
|
SHORT,
|
||||||
|
CHARACTER
|
||||||
|
}
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() };
|
||||||
|
|
|
@ -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(" := @")
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user