com.codename1.tools.translator.bytecodes.ArithmeticExpression Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.codename1.tools.translator.bytecodes;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
/**
*
* @author shannah
*/
public class ArithmeticExpression extends Instruction implements AssignableExpression{
public static final int OPCODE=-2;
private ArithmeticExpression subExpression;
private ArithmeticExpression subExpression2;
private Instruction lastInstruction;
private ArithmeticExpression() {
super(OPCODE);
}
@Override
public boolean isConstant() {
if (lastInstruction != null && lastInstruction.isConstant()) {
return true;
}
if (subExpression2 == null && subExpression != null && subExpression.isConstant()) {
return true;
}
if (subExpression2 != null && subExpression != null && subExpression.isConstant() && subExpression2.isConstant()) {
return true;
}
return super.isConstant();
}
@Override
public void addDependencies(List dependencyList) {
if (subExpression != null) {
subExpression.addDependencies(dependencyList);
}
if (subExpression2 != null) {
subExpression2.addDependencies(dependencyList);
}
if (lastInstruction != null) {
lastInstruction.addDependencies(dependencyList);
}
}
@Override
public void appendInstruction(StringBuilder b) {
if (subExpression != null) {
subExpression.appendInstruction(b);
}
if (subExpression2 != null) {
subExpression2.appendInstruction(b);
}
if (lastInstruction != null) {
lastInstruction.appendInstruction(b);
}
}
@Override
public void appendInstruction(StringBuilder b, List l) {
if (subExpression != null) {
subExpression.appendInstruction(b, l);
}
if (subExpression2 != null) {
subExpression2.appendInstruction(b, l);
}
if (lastInstruction != null) {
lastInstruction.appendInstruction(b, l);
}
}
public static int tryReduce(List instructions, int index) {
Instruction instr = instructions.get(index);
if (isArithmeticOp(instr)) {
Instruction op = instr;
if (isBinaryOp(op)) {
if (index < 2) {
return -1;
}
Instruction arg1 = instructions.get(index-2);
Instruction arg2 = instructions.get(index-1);
if (!isArg(arg1) || !isArg(arg2)) {
return -1;
}
ArithmeticExpression expr = new ArithmeticExpression();
expr.lastInstruction = instr;
if (arg1 instanceof ArithmeticExpression) {
expr.subExpression = (ArithmeticExpression)arg1;
} else {
expr.subExpression = new ArithmeticExpression();
expr.subExpression.lastInstruction = arg1;
}
if (arg2 instanceof ArithmeticExpression) {
expr.subExpression2 = (ArithmeticExpression)arg2;
} else {
expr.subExpression2 = new ArithmeticExpression();
expr.subExpression2.lastInstruction = arg2;
}
instructions.remove(index-2);
instructions.remove(index-2);
instructions.remove(index-2);
instructions.add(index-2, expr);
return index-2;
} else {
if (index < 1) {
return -1;
}
Instruction arg = instructions.get(index-1);
if (!isArg(arg)) {
return -1;
}
ArithmeticExpression expr = new ArithmeticExpression();
expr.lastInstruction = instr;
if (arg instanceof ArithmeticExpression) {
expr.subExpression = (ArithmeticExpression)arg;
} else {
expr.subExpression = new ArithmeticExpression();
expr.subExpression.lastInstruction = arg;
}
instructions.remove(index-1);
instructions.remove(index-1);
instructions.add(index-1, expr);
return index-1;
}
}
return -1;
}
public static boolean isArg(Instruction instr) {
if (instr instanceof ArithmeticExpression) {
return true;
}
if (instr instanceof AssignableExpression) {
StringBuilder dummy = new StringBuilder();
if (((AssignableExpression)instr).assignTo(null, dummy)) {
return true;
}
}
int opcode = instr.getOpcode();
switch (opcode) {
case Opcodes.FLOAD:
case Opcodes.DLOAD:
case Opcodes.ILOAD:
case Opcodes.LLOAD:
case org.objectweb.asm.Opcodes.ICONST_0:
case org.objectweb.asm.Opcodes.ICONST_1:
case org.objectweb.asm.Opcodes.ICONST_2:
case org.objectweb.asm.Opcodes.ICONST_3:
case org.objectweb.asm.Opcodes.ICONST_4:
case org.objectweb.asm.Opcodes.ICONST_5:
case org.objectweb.asm.Opcodes.ICONST_M1:
case org.objectweb.asm.Opcodes.LCONST_0:
case org.objectweb.asm.Opcodes.LCONST_1:
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
case org.objectweb.asm.Opcodes.BIPUSH:
case org.objectweb.asm.Opcodes.SIPUSH:
case Opcodes.LDC:
return true;
}
return false;
}
public static boolean isBinaryOp(Instruction instr) {
switch (instr.getOpcode()) {
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.IUSHR:
case Opcodes.LUSHR:
case Opcodes.DCMPG:
case Opcodes.DCMPL:
case Opcodes.FCMPG:
case Opcodes.FCMPL:
case Opcodes.LCMP:
case Opcodes.IOR:
case Opcodes.LOR:
case Opcodes.IXOR:
case Opcodes.LXOR:
case Opcodes.IAND:
case Opcodes.LAND:
case Opcodes.FADD:
case Opcodes.DADD:
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FSUB:
case Opcodes.DSUB:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FDIV:
case Opcodes.DDIV:
case Opcodes.LDIV:
case Opcodes.IDIV:
case Opcodes.IREM:
case Opcodes.FREM:
case Opcodes.DREM:
case Opcodes.LREM:
case Opcodes.FMUL:
case Opcodes.DMUL:
case Opcodes.IMUL:
case Opcodes.LMUL:
return true;
}
return false;
}
@Override
public boolean isOptimized() {
return true;
}
public static boolean isArithmeticOp(Instruction instr) {
switch (instr.getOpcode()) {
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.IUSHR:
case Opcodes.LUSHR:
case Opcodes.DCMPG:
case Opcodes.DCMPL:
case Opcodes.FCMPG:
case Opcodes.FCMPL:
case Opcodes.LCMP:
case Opcodes.FNEG:
case Opcodes.DNEG:
case Opcodes.INEG:
case Opcodes.D2F:
case Opcodes.D2I:
case Opcodes.D2L:
case Opcodes.F2D:
case Opcodes.F2I:
case Opcodes.F2L:
case Opcodes.L2D:
case Opcodes.L2F:
case Opcodes.L2I:
case Opcodes.I2L:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2D:
case Opcodes.I2F:
case Opcodes.I2S:
case Opcodes.IOR:
case Opcodes.LOR:
case Opcodes.IXOR:
case Opcodes.LXOR:
case Opcodes.IAND:
case Opcodes.LAND:
case Opcodes.FADD:
case Opcodes.DADD:
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FSUB:
case Opcodes.DSUB:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FDIV:
case Opcodes.DDIV:
case Opcodes.LDIV:
case Opcodes.IDIV:
case Opcodes.IREM:
case Opcodes.FREM:
case Opcodes.DREM:
case Opcodes.LREM:
case Opcodes.FMUL:
case Opcodes.DMUL:
case Opcodes.IMUL:
case Opcodes.LMUL:
return true;
}
return false;
}
public String getExpressionAsString() {
Instruction instr = lastInstruction;
int opcode = lastInstruction.getOpcode();
if (subExpression == null) {
// This is the root of it... probably an FLOAD
if (lastInstruction instanceof AssignableExpression && !(lastInstruction instanceof ArithmeticExpression)) {
StringBuilder out = new StringBuilder();
if (((AssignableExpression)lastInstruction).assignTo(null, out)) {
String strOut = out.toString();
if (strOut.trim().isEmpty()) {
throw new RuntimeException("Instruction produces blank string output: "+lastInstruction);
}
if (strOut == null || "null".equals(strOut)) {
throw new RuntimeException("ArithmeticExpression produced null value. This shouldn't happen: "+lastInstruction);
}
return strOut;
}
}
if (lastInstruction instanceof VarOp) {
VarOp var = (VarOp)lastInstruction;
switch (opcode) {
case Opcodes.FLOAD: {
return "flocals_"+var.getIndex()+"_";
}
case Opcodes.DLOAD: {
return "dlocals_"+var.getIndex()+"_";
}
case Opcodes.ILOAD: {
return "ilocals_"+var.getIndex()+"_";
}
case Opcodes.LLOAD: {
return "llocals_"+var.getIndex()+"_";
}
case org.objectweb.asm.Opcodes.ICONST_0: {
return "0";
}
case org.objectweb.asm.Opcodes.ICONST_1: {
return "1";
}
case org.objectweb.asm.Opcodes.ICONST_2: {
return "2";
}
case org.objectweb.asm.Opcodes.ICONST_3: {
return "3";
}
case org.objectweb.asm.Opcodes.ICONST_4: {
return "4";
}
case org.objectweb.asm.Opcodes.ICONST_5: {
return "5";
}
case org.objectweb.asm.Opcodes.ICONST_M1: {
return "(-1)";
}
case org.objectweb.asm.Opcodes.LCONST_0: {
return "((JAVA_LONG)0)";
}
case Opcodes.DCONST_0: {
return "((JAVA_DOUBLE)0)";
}
case Opcodes.DCONST_1: {
return "((JAVA_DOUBLE)1)";
}
case Opcodes.FCONST_0: {
return "((JAVA_FLOAT)0)";
}
case Opcodes.FCONST_1: {
return "((JAVA_FLOAT)1)";
}
case Opcodes.FCONST_2: {
return "((JAVA_FLOAT)2";
}
case org.objectweb.asm.Opcodes.LCONST_1: {
return "((JAVA_LONG)1)";
}
case org.objectweb.asm.Opcodes.BIPUSH:
case org.objectweb.asm.Opcodes.SIPUSH: {
return String.valueOf(var.getIndex());
}
default: {
throw new RuntimeException("Unsupported Opcode in ArithmeticExpression: "+opcode+" "+var);
}
}
} else {
switch (instr.getOpcode()) {
case org.objectweb.asm.Opcodes.ICONST_0: {
return "0";
}
case org.objectweb.asm.Opcodes.ICONST_1: {
return "1";
}
case org.objectweb.asm.Opcodes.ICONST_2: {
return "2";
}
case org.objectweb.asm.Opcodes.ICONST_3: {
return "3";
}
case org.objectweb.asm.Opcodes.ICONST_4: {
return "4";
}
case org.objectweb.asm.Opcodes.ICONST_5: {
return "5";
}
case org.objectweb.asm.Opcodes.ICONST_M1: {
return "(-1)";
}
case org.objectweb.asm.Opcodes.LCONST_0: {
return "((JAVA_LONG)0)";
}
case org.objectweb.asm.Opcodes.LCONST_1: {
return "(JAVA_LONG)1";
}
case org.objectweb.asm.Opcodes.BIPUSH: {
if (instr instanceof BasicInstruction) {
return String.valueOf(((BasicInstruction) instr).getValue());
}
break;
}
case org.objectweb.asm.Opcodes.LDC: {
if (instr instanceof Ldc) {
Ldc ldc = (Ldc) instr;
return ldc.getValueAsString();
}
break;
}
default: {
throw new RuntimeException("Unsupported Opcode in ArithmeticExpression: "+opcode+" "+instr);
}
}
}
} else {
switch (opcode) {
case Opcodes.ISHL: {
return "BC_ISHL_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.ISHR: {
return "BC_ISHR_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.LSHL: {
return "BC_LSHL_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.LSHR: {
return "BC_LSHR_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.IUSHR: {
return "BC_IUSHR_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.LUSHR: {
return "BC_LUSHR_EXPR("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.DCMPG:
case Opcodes.DCMPL:
case Opcodes.FCMPG:
case Opcodes.FCMPL:
case Opcodes.LCMP: {
return "CN1_CMP_EXPR("+subExpression.getExpressionAsString().trim() + ", " + subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.D2F: {
return "((JAVA_FLOAT)" + subExpression.getExpressionAsString().trim() + ")";
}
case Opcodes.F2D: {
return subExpression.getExpressionAsString().trim();
}
case Opcodes.F2I: {
return "((JAVA_INT)" + subExpression.getExpressionAsString().trim() + ")";
}
case Opcodes.F2L: {
return "((JAVA_LONG)" + subExpression.getExpressionAsString().trim() + ")";
}
case Opcodes.D2I: {
return "((JAVA_INT)" + subExpression.getExpressionAsString().trim() + ")";
}
case Opcodes.D2L: {
return "((JAVA_LONG)" + subExpression.getExpressionAsString().trim() + ")";
}
case Opcodes.I2B: {
return "(("+subExpression.getExpressionAsString()+" << 24) >> 24)";
}
case Opcodes.I2C: {
return "("+subExpression.getExpressionAsString().trim()+" & 0xffff)";
}
case Opcodes.I2D: {
return "((JAVA_DOUBLE)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.I2F: {
return "((JAVA_FLOAT)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.I2L: {
return "((JAVA_LONG)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.I2S: {
return "(("+subExpression.getExpressionAsString().trim()+" << 16) >> 16)";
}
case Opcodes.L2D: {
return "((JAVA_DOUBLE)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.L2F: {
return "((JAVA_FLOAT)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.L2I: {
return "((JAVA_INT)"+subExpression.getExpressionAsString().trim()+")";
}
case Opcodes.IAND:
case Opcodes.LAND: {
return "(" + subExpression.getExpressionAsString().trim() + " & " + subExpression2.getExpressionAsString().trim() + ")";
}
case Opcodes.IOR:
case Opcodes.LOR: {
return "(" + subExpression.getExpressionAsString().trim() + " | " + subExpression2.getExpressionAsString().trim() + ")";
}
case Opcodes.IXOR:
case Opcodes.LXOR: {
return "(" + subExpression.getExpressionAsString().trim() + " ^ " + subExpression2.getExpressionAsString().trim() + ")";
}
case Opcodes.DADD:
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FADD: {
return "(" + subExpression.getExpressionAsString().trim() + " + " + subExpression2.getExpressionAsString().trim() + ")";
}
case Opcodes.DSUB:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FSUB: {
return "(" + subExpression.getExpressionAsString().trim() + " - " + subExpression2.getExpressionAsString().trim() + ")";
}
case Opcodes.DMUL:
case Opcodes.IMUL:
case Opcodes.LMUL:
case Opcodes.FMUL: {
return "("+subExpression.getExpressionAsString().trim() + " * " + subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.DDIV:
case Opcodes.IDIV:
case Opcodes.LDIV:
case Opcodes.FDIV: {
return "("+subExpression.getExpressionAsString().trim() + " / " + subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.FREM:
case Opcodes.DREM: {
return "fmod("+subExpression.getExpressionAsString().trim() + ", "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.LREM:
case Opcodes.IREM: {
if (subExpression2.getExpressionAsString() == null || "null".equals(subExpression2.getExpressionAsString())) {
throw new RuntimeException("2nd param of REM is null. Should never happen. Expression is "+subExpression2+" with last instruction "+subExpression2.lastInstruction);
}
return "("+subExpression.getExpressionAsString().trim() + " % "+subExpression2.getExpressionAsString().trim()+")";
}
case Opcodes.FNEG:
case Opcodes.INEG:
case Opcodes.LNEG:
case Opcodes.DNEG:
return "(-("+subExpression.getExpressionAsString().trim()+"))";
default: {
throw new RuntimeException("Unsupported Opcode in ArithmeticExpression: "+opcode+" "+instr);
}
}
}
throw new RuntimeException("Did not return a value in getExpressionAsString() with lastInstruction "+lastInstruction+" subExpression "+subExpression+" and subExpression2 "+subExpression2);
}
@Override
public boolean assignTo(String varName, StringBuilder sb) {
if (varName != null) {
sb.append(varName).append("=");
}
sb.append(getExpressionAsString());
if (varName != null) {
sb.append(";\n");
}
return true;
}
}