summaryrefslogtreecommitdiff
path: root/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java')
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java614
1 files changed, 614 insertions, 0 deletions
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
new file mode 100644
index 0000000000..b8f29a6a2b
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
@@ -0,0 +1,614 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Extended list of instructions, providing pseudo-instructions which
+ * are easier to use than the standard ones.
+ *
+ * @author Michel Schinz, Thomas Friedli
+ * @version 1.0
+ */
+
+public class JExtendedCode extends JCode {
+ public final static int COND_EQ = 0;
+ public final static int COND_NE = 1;
+ public final static int COND_LT = 2;
+ public final static int COND_GE = 3;
+ public final static int COND_GT = 4;
+ public final static int COND_LE = 5;
+
+ private final JOpcode[] forbidden = new JOpcode[0];
+ private final JOpcode[] nothingToDo = new JOpcode[0];
+
+ private final JOpcode[][][] typeConversions = {
+ {
+ /* T_BOOLEAN -> T_BOOLEAN */ nothingToDo,
+ /* T_BOOLEAN -> T_CHAR */ forbidden,
+ /* T_BOOLEAN -> T_FLOAT */ forbidden,
+ /* T_BOOLEAN -> T_DOUBLE */ forbidden,
+ /* T_BOOLEAN -> T_BYTE */ forbidden,
+ /* T_BOOLEAN -> T_SHORT */ forbidden,
+ /* T_BOOLEAN -> T_INT */ forbidden,
+ /* T_BOOLEAN -> T_LONG */ forbidden
+ },
+ {
+ /* T_CHAR -> T_BOOLEAN */ forbidden,
+ /* T_CHAR -> T_CHAR */ nothingToDo,
+ /* T_CHAR -> T_FLOAT */ {JOpcode.I2F},
+ /* T_CHAR -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_CHAR -> T_BYTE */ {JOpcode.I2B},
+ /* T_CHAR -> T_SHORT */ {JOpcode.I2S},
+ /* T_CHAR -> T_INT */ nothingToDo,
+ /* T_CHAR -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_FLOAT -> T_BOOLEAN */ forbidden,
+ /* T_FLOAT -> T_CHAR */ {JOpcode.F2I, JOpcode.I2C},
+ /* T_FLOAT -> T_FLOAT */ nothingToDo,
+ /* T_FLOAT -> T_DOUBLE */ {JOpcode.F2D},
+ /* T_FLOAT -> T_BYTE */ {JOpcode.F2I, JOpcode.I2B},
+ /* T_FLOAT -> T_SHORT */ {JOpcode.F2I, JOpcode.I2S},
+ /* T_FLOAT -> T_INT */ {JOpcode.F2I},
+ /* T_FLOAT -> T_LONG */ {JOpcode.F2L}
+ },
+ {
+ /* T_DOUBLE -> T_BOOLEAN */ forbidden,
+ /* T_DOUBLE -> T_CHAR */ {JOpcode.D2I, JOpcode.I2C},
+ /* T_DOUBLE -> T_FLOAT */ {JOpcode.D2F},
+ /* T_DOUBLE -> T_DOUBLE */ nothingToDo,
+ /* T_DOUBLE -> T_BYTE */ {JOpcode.D2I, JOpcode.I2B},
+ /* T_DOUBLE -> T_SHORT */ {JOpcode.D2I, JOpcode.I2S},
+ /* T_DOUBLE -> T_INT */ {JOpcode.D2I},
+ /* T_DOUBLE -> T_LONG */ {JOpcode.D2L}
+ },
+ {
+ /* T_BYTE -> T_BOOLEAN */ forbidden,
+ /* T_BYTE -> T_CHAR */ {JOpcode.I2C},
+ /* T_BYTE -> T_FLOAT */ {JOpcode.I2F},
+ /* T_BYTE -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_BYTE -> T_BYTE */ nothingToDo,
+ /* T_BYTE -> T_SHORT */ nothingToDo,
+ /* T_BYTE -> T_INT */ nothingToDo,
+ /* T_BYTE -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_SHORT -> T_BOOLEAN */ forbidden,
+ /* T_SHORT -> T_CHAR */ nothingToDo,
+ /* T_SHORT -> T_FLOAT */ {JOpcode.I2F},
+ /* T_SHORT -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_SHORT -> T_BYTE */ {JOpcode.I2B},
+ /* T_SHORT -> T_SHORT */ nothingToDo,
+ /* T_SHORT -> T_INT */ nothingToDo,
+ /* T_SHORT -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_INT -> T_BOOLEAN */ forbidden,
+ /* T_INT -> T_CHAR */ {JOpcode.I2C},
+ /* T_INT -> T_FLOAT */ {JOpcode.I2F},
+ /* T_INT -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_INT -> T_BYTE */ {JOpcode.I2B},
+ /* T_INT -> T_SHORT */ {JOpcode.I2S},
+ /* T_INT -> T_INT */ nothingToDo,
+ /* T_INT -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_LONG -> T_BOOLEAN */ forbidden,
+ /* T_LONG -> T_CHAR */ {JOpcode.L2I, JOpcode.I2C},
+ /* T_LONG -> T_FLOAT */ {JOpcode.L2F},
+ /* T_LONG -> T_DOUBLE */ {JOpcode.L2D},
+ /* T_LONG -> T_BYTE */ {JOpcode.L2I, JOpcode.I2B},
+ /* T_LONG -> T_SHORT */ {JOpcode.L2I, JOpcode.I2S},
+ /* T_LONG -> T_INT */ {JOpcode.L2I},
+ /* T_LONG -> T_LONG */ nothingToDo
+ }
+ };
+
+ public JExtendedCode(FJBGContext context,
+ JClass clazz,
+ JMethod owner) {
+ super(context, clazz, owner);
+ }
+
+ public void emitPUSH(boolean value) { emitPUSH(value ? 1 : 0); }
+ public void emitPUSH(Boolean value) { emitPUSH(value.booleanValue()); }
+
+ public void emitPUSH(byte value) { emitBIPUSH(value); }
+ public void emitPUSH(Byte value) { emitPUSH(value.byteValue()); }
+
+ public void emitPUSH(short value) { emitSIPUSH(value); }
+ public void emitPUSH(Short value) { emitPUSH(value.shortValue()); }
+
+ // TODO check that we do the right thing here
+ public void emitPUSH(char value) { emitPUSH((int)value); }
+ public void emitPUSH(Character value) { emitPUSH(value.charValue()); }
+
+ public void emitPUSH(int value) {
+ switch (value) {
+ case -1: emitICONST_M1(); break;
+ case 0: emitICONST_0(); break;
+ case 1: emitICONST_1(); break;
+ case 2: emitICONST_2(); break;
+ case 3: emitICONST_3(); break;
+ case 4: emitICONST_4(); break;
+ case 5: emitICONST_5(); break;
+ default: emitPUSH_index(pool.addInteger(value)); break;
+ }
+ }
+ public void emitPUSH(Integer value) { emitPUSH(value.intValue()); }
+
+ public void emitPUSH(long value) {
+ if (value == 0L)
+ emitLCONST_0();
+ else if (value == 1L)
+ emitLCONST_1();
+ else
+ emitLDC2_W(value);
+ }
+ public void emitPUSH(Long value) { emitPUSH(value.longValue()); }
+
+ public void emitPUSH(float value) {
+ if (value == 0.0F)
+ emitFCONST_0();
+ else if (value == 1.0F)
+ emitFCONST_1();
+ else if (value == 2.0F)
+ emitFCONST_2();
+ else
+ emitPUSH_index(pool.addFloat(value));
+ }
+ public void emitPUSH(Float value) { emitPUSH(value.floatValue()); }
+
+ public void emitPUSH(double value) {
+ if (value == 0.0)
+ emitDCONST_0();
+ else if (value == 1.0)
+ emitDCONST_1();
+ else
+ emitLDC2_W(value);
+ }
+ public void emitPUSH(Double value) { emitPUSH(value.doubleValue()); }
+
+ public void emitPUSH(String s) {
+ emitPUSH_index(pool.addString(s));
+ }
+
+ /** Pushes a class literal on the stack */
+ public void emitPUSH(JReferenceType type) {
+ assert owner.owner.major >= 49;
+ emitPUSH_index(pool.addClass(type.getDescriptor()));
+ }
+
+ protected void emitPUSH_index(int index) {
+ if (index <= 0xFF)
+ emitU1(JOpcode.LDC, index);
+ else
+ emitU2(JOpcode.LDC_W, index);
+ }
+
+ public void emitLOAD(int index, JType type) {
+ JOpcode opcode;
+
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ switch (index) {
+ case 0: emitILOAD_0(); return;
+ case 1: emitILOAD_1(); return;
+ case 2: emitILOAD_2(); return;
+ case 3: emitILOAD_3(); return;
+ default: opcode = JOpcode.ILOAD;
+ } break;
+ case JType.T_FLOAT:
+ switch (index) {
+ case 0: emitFLOAD_0(); return;
+ case 1: emitFLOAD_1(); return;
+ case 2: emitFLOAD_2(); return;
+ case 3: emitFLOAD_3(); return;
+ default: opcode = JOpcode.FLOAD;
+ } break;
+ case JType.T_LONG:
+ switch (index) {
+ case 0: emitLLOAD_0(); return;
+ case 1: emitLLOAD_1(); return;
+ case 2: emitLLOAD_2(); return;
+ case 3: emitLLOAD_3(); return;
+ default: opcode = JOpcode.LLOAD;
+ } break;
+ case JType.T_DOUBLE:
+ switch (index) {
+ case 0: emitDLOAD_0(); return;
+ case 1: emitDLOAD_1(); return;
+ case 2: emitDLOAD_2(); return;
+ case 3: emitDLOAD_3(); return;
+ default: opcode = JOpcode.DLOAD;
+ } break;
+ case JType.T_ARRAY: case JType.T_OBJECT:
+ switch (index) {
+ case 0: emitALOAD_0(); return;
+ case 1: emitALOAD_1(); return;
+ case 2: emitALOAD_2(); return;
+ case 3: emitALOAD_3(); return;
+ default: opcode = JOpcode.ALOAD;
+ } break;
+ default:
+ throw new IllegalArgumentException("invalid type for load "+type);
+ }
+
+ if (index > 0xFF)
+ emitWIDE(opcode, index);
+ else
+ emitU1(opcode, index);
+ }
+ public void emitLOAD(JLocalVariable var) {
+ emitLOAD(var.index, var.type);
+ }
+
+ public void emitSTORE(int index, JType type) {
+ JOpcode opcode;
+
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ switch (index) {
+ case 0: emitISTORE_0(); return;
+ case 1: emitISTORE_1(); return;
+ case 2: emitISTORE_2(); return;
+ case 3: emitISTORE_3(); return;
+ default: opcode = JOpcode.ISTORE;
+ } break;
+ case JType.T_FLOAT:
+ switch (index) {
+ case 0: emitFSTORE_0(); return;
+ case 1: emitFSTORE_1(); return;
+ case 2: emitFSTORE_2(); return;
+ case 3: emitFSTORE_3(); return;
+ default: opcode = JOpcode.FSTORE;
+ } break;
+ case JType.T_LONG:
+ switch (index) {
+ case 0: emitLSTORE_0(); return;
+ case 1: emitLSTORE_1(); return;
+ case 2: emitLSTORE_2(); return;
+ case 3: emitLSTORE_3(); return;
+ default: opcode = JOpcode.LSTORE;
+ } break;
+ case JType.T_DOUBLE:
+ switch (index) {
+ case 0: emitDSTORE_0(); return;
+ case 1: emitDSTORE_1(); return;
+ case 2: emitDSTORE_2(); return;
+ case 3: emitDSTORE_3(); return;
+ default: opcode = JOpcode.DSTORE;
+ } break;
+ case JType.T_ARRAY: case JType.T_OBJECT: case JType.T_ADDRESS:
+ switch (index) {
+ case 0: emitASTORE_0(); return;
+ case 1: emitASTORE_1(); return;
+ case 2: emitASTORE_2(); return;
+ case 3: emitASTORE_3(); return;
+ default: opcode = JOpcode.ASTORE;
+ } break;
+ default:
+ throw new IllegalArgumentException("invalid type for store "+type);
+ }
+
+ if (index > 0xFF)
+ emitWIDE(opcode, index);
+ else
+ emitU1(opcode, index);
+ }
+ public void emitSTORE(JLocalVariable var) {
+ emitSTORE(var.index, var.type);
+ }
+
+ public void emitALOAD(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ emitBALOAD();
+ break;
+ case JType.T_CHAR:
+ emitCALOAD();
+ break;
+ case JType.T_SHORT:
+ emitSALOAD();
+ break;
+ case JType.T_INT:
+ emitIALOAD();
+ break;
+ case JType.T_FLOAT:
+ emitFALOAD();
+ break;
+ case JType.T_LONG:
+ emitLALOAD();
+ break;
+ case JType.T_DOUBLE:
+ emitDALOAD();
+ break;
+ case JType.T_ARRAY:
+ case JType.T_OBJECT:
+ emitAALOAD();
+ break;
+ default:
+ throw new IllegalArgumentException("invalid type for aload " + type);
+ }
+ }
+
+ public void emitASTORE(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ emitBASTORE();
+ break;
+ case JType.T_CHAR:
+ emitCASTORE();
+ break;
+ case JType.T_SHORT:
+ emitSASTORE();
+ break;
+ case JType.T_INT:
+ emitIASTORE();
+ break;
+ case JType.T_FLOAT:
+ emitFASTORE();
+ break;
+ case JType.T_LONG:
+ emitLASTORE();
+ break;
+ case JType.T_DOUBLE:
+ emitDASTORE();
+ break;
+ case JType.T_ARRAY:
+ case JType.T_OBJECT:
+ emitAASTORE();
+ break;
+ default:
+ throw new IllegalArgumentException("invalid type for astore " + type);
+ }
+ }
+
+ public void emitRETURN(JType type) {
+ if (type.isValueType()) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ case JType.T_CHAR:
+ case JType.T_SHORT:
+ case JType.T_INT:
+ emitIRETURN();
+ break;
+ case JType.T_FLOAT:
+ emitFRETURN();
+ break;
+ case JType.T_LONG:
+ emitLRETURN();
+ break;
+ case JType.T_DOUBLE:
+ emitDRETURN();
+ break;
+ }
+ } else if (type.isArrayType() || type.isObjectType())
+ emitARETURN();
+ else if (type == JType.VOID)
+ emitRETURN();
+ else
+ throw new IllegalArgumentException("invalid type for RETURN " + type);
+ }
+
+ public void emitADD(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ emitIADD(); break;
+ case JType.T_FLOAT:
+ emitFADD(); break;
+ case JType.T_LONG:
+ emitLADD(); break;
+ case JType.T_DOUBLE:
+ emitDADD(); break;
+ }
+ }
+
+ /**
+ * Emits a basic type conversion instruction choosen according to the
+ * types given in parameter.
+ *
+ * @param fromType The type of the value to be cast into another type.
+ * @param toType The type the value will be cast into.
+ */
+ public void emitT2T(JType fromType, JType toType) {
+ assert fromType.getTag() >= JType.T_BOOLEAN
+ && fromType.getTag() <= JType.T_LONG
+ && toType.getTag() >= JType.T_BOOLEAN
+ && toType.getTag() <= JType.T_LONG;
+
+ JOpcode[] conv = typeConversions[fromType.getTag() - 4][toType.getTag() - 4];
+ if (conv == forbidden) {
+ throw new Error("inconvertible types : " + fromType.toString()
+ + " -> " + toType.toString());
+ } else if (conv != nothingToDo) {
+ for (int i = 0; i < conv.length; i++) {
+ emit(conv[i]);
+ }
+ }
+ }
+
+ public void emitIF(int cond, Label label) throws OffsetTooBigException {
+ assert cond >= COND_EQ && cond <= COND_LE;
+ emitU2(JOpcode.OPCODES[153 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[153 + cond], offset);
+ }
+ public void emitIF(int cond) throws OffsetTooBigException {
+ emitIF(cond, 0);
+ }
+
+ public void emitIF_ICMP(int cond, Label label) throws OffsetTooBigException {
+ assert cond >= COND_EQ && cond <= COND_LE;
+ emitU2(JOpcode.OPCODES[159 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF_ICMP(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[159 + cond], offset);
+ }
+ public void emitIF_ICMP(int cond) throws OffsetTooBigException {
+ emitIF_ICMP(cond, 0);
+ }
+
+ public void emitIF_ACMP(int cond, Label label) throws OffsetTooBigException {
+ assert cond == COND_EQ || cond == COND_NE;
+ emitU2(JOpcode.OPCODES[165 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF_ACMP(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[165 + cond], offset);
+ }
+ public void emitIF_ACMP(int cond) throws OffsetTooBigException {
+ emitIF_ACMP(cond, 0);
+ }
+
+ public void emitGOTO_maybe_W(Label label, boolean defaultToWide) {
+ if (label.anchored)
+ emitGOTO_maybe_W(label.targetPC);
+ else {
+ if (defaultToWide)
+ emitGOTO_W(label);
+ else {
+ try {
+ emitGOTO(label);
+ } catch (OffsetTooBigException e) {
+ throw new Error(e);
+ }
+ }
+ }
+ }
+
+ public void emitGOTO_maybe_W(int targetPC) {
+ int offset = targetPC - (getPC() + 1);
+ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)
+ emitGOTO_W(targetPC);
+ else {
+ try {
+ emitGOTO(targetPC);
+ } catch (OffsetTooBigException e) {
+ throw new Error(e);
+ }
+ }
+ }
+
+ /**
+ * Emits a switch instruction choosen according to the caracteristics
+ * of the given list of keys and a default maxRate.
+ *
+ * @param keySets The array of all keys that must be compared to the
+ * value on stack.
+ * @param branches The labels representing the jump addresses linked
+ * with the corresponding keys.
+ * @param defaultBranch The label representing the default branch
+ * address.
+ */
+ public void emitSWITCH(int[][] keySets,
+ Label[] branches,
+ Label defaultBranch,
+ double minDensity) {
+ assert keySets.length == branches.length;
+
+ int flatSize = 0;
+ for (int i = 0; i < keySets.length; ++i)
+ flatSize += keySets[i].length;
+
+ int[] flatKeys = new int[flatSize];
+ Label[] flatBranches = new Label[flatSize];
+ int flatI = 0;
+ for (int i = 0; i < keySets.length; ++i) {
+ Label branch = branches[i];
+ int[] keys = keySets[i];
+ for (int j = 0; j < keys.length; ++j) {
+ flatKeys[flatI] = keys[j];
+ flatBranches[flatI] = branch;
+ }
+ ++flatI;
+ }
+ assert flatI == flatSize;
+ emitSWITCH(flatKeys, flatBranches, defaultBranch, minDensity);
+ }
+
+ /**
+ * Emits a switch instruction choosen according to the caracteristics
+ * of the given list of keys and a given maxRate.
+ *
+ * @param keys The array of all keys that must be compared to the
+ * value on stack.
+ * @param branches The labels representing the jump addresses linked
+ * with the corresponding keys.
+ * @param defaultBranch The label representing the default branch
+ * address.
+ * @param minDensity The minimum density to use for TABLESWITCH.
+ */
+ public void emitSWITCH(int[] keys,
+ Label[] branches,
+ Label defaultBranch,
+ double minDensity) {
+ assert keys.length == branches.length;
+
+ // sorting the tables
+ // FIXME use quicksort
+ for (int i = 1; i < keys.length; i++) {
+ for (int j = 1; j <= keys.length - i; j++) {
+ if (keys[j] < keys[j - 1]) {
+ int tmp = keys[j];
+ keys[j] = keys[j - 1];
+ keys[j - 1] = tmp;
+
+ Label tmp_l = branches[j];
+ branches[j] = branches[j - 1];
+ branches[j - 1] = tmp_l;
+ }
+ }
+ }
+
+ int keyMin = keys[0], keyMax = keys[keys.length - 1];
+ int keyRange = keyMax - keyMin + 1;
+ if ((double)keys.length / (double)keyRange >= minDensity) {
+ // Keys are dense enough, use a table in which holes are
+ // filled with defaultBranch.
+ int[] newKeys = new int[keyRange];
+ Label[] newBranches = new Label[keyRange];
+ int oldPos = 0;
+ for (int i = 0; i < keyRange; ++i) {
+ int key = keyMin + i;
+ newKeys[i] = key;
+ if (keys[oldPos] == key) {
+ newBranches[i] = branches[oldPos];
+ ++oldPos;
+ } else
+ newBranches[i] = defaultBranch;
+ }
+ assert oldPos == keys.length;
+ emitTABLESWITCH(newKeys, newBranches, defaultBranch);
+ } else
+ emitLOOKUPSWITCH(keys, branches, defaultBranch);
+ }
+
+ /**
+ * Emits a method invocation instruction choosen according to
+ * the caracteristics of the given method.
+ *
+ * @param method The method to be invoked.
+ */
+ public void emitINVOKE(JMethod method) {
+ String mName = method.getName();
+ String cName = method.getOwner().getName();
+ JMethodType mType = (JMethodType)method.getType();
+ if (method.isStatic())
+ emitINVOKESTATIC(cName, mName, mType);
+ else if (method.getOwner().isInterface())
+ emitINVOKEINTERFACE(cName, mName, mType);
+ else
+ emitINVOKEVIRTUAL(cName, mName, mType);
+ }
+
+}