X-Git-Url: http://git.megacz.com/?p=org.ibex.classgen.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fclassgen%2FMethodGen.java;h=16c53edbb22571fe9432484bca9607105bde99dd;hp=383ed57e865b1b1b53a8580b6fe1ebd74b4ecca5;hb=017306c392932fe7db2f1123b1bf733832a03419;hpb=94cebd4c12247ae7fd0a4b0cc66609fead0efece
diff --git a/src/org/ibex/classgen/MethodGen.java b/src/org/ibex/classgen/MethodGen.java
index 383ed57..16c53ed 100644
--- a/src/org/ibex/classgen/MethodGen.java
+++ b/src/org/ibex/classgen/MethodGen.java
@@ -3,8 +3,6 @@ package org.ibex.classgen;
import java.io.*;
import java.util.*;
-// FEATURE: Support WIDE bytecodes
-
/** A class representing a method in a generated classfile
@see ClassGen#addMethod */
public class MethodGen implements CGConst {
@@ -193,6 +191,7 @@ public class MethodGen implements CGConst {
break;
case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
+ if(n >= maxLocals) maxLocals = n + 1;
if(n >= 0 && n <= 3) {
byte base = 0;
switch(op) {
@@ -209,7 +208,6 @@ public class MethodGen implements CGConst {
}
op = (byte)((base&0xff) + n);
} else {
- if(n >= maxLocals) maxLocals = n + 1;
arg = N(n);
}
break;
@@ -261,7 +259,7 @@ public class MethodGen implements CGConst {
@see MethodGen.TSI
@see MethodGen.LSI
*/
- public static class SI {
+ public static abstract class SI {
public final Object[] targets;
public Object defaultTarget;
@@ -273,7 +271,9 @@ public class MethodGen implements CGConst {
public int size() { return targets.length; }
public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
- public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
+ public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
+
+ abstract int length();
}
/** This class represents the arguments to the TABLESWITCH bytecode */
@@ -287,6 +287,8 @@ public class MethodGen implements CGConst {
}
public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
+
+ int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default
}
/** This class represents the arguments to the LOOKUPSWITCH bytecode */
@@ -297,6 +299,8 @@ public class MethodGen implements CGConst {
this.vals = new int[size];
}
public final void setVal(int pos, int val) { vals[pos] = val; }
+
+ int length() { return 8 + targets.length * 8; } // key/val per target, default, count
}
/** This class represents the arguments to byecodes that take two integer arguments. */
@@ -305,6 +309,14 @@ public class MethodGen implements CGConst {
public int i2;
public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
}
+
+ public static class Wide {
+ public final byte op;
+ public final int varNum;
+ public final int n;
+ Wide(byte op, int varNum) { this(op,varNum,0); }
+ Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
+ }
/** Sets the maximum number of locals in the function to maxLocals. NOTE: This defaults to 0 and is automatically increased as
necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
@@ -341,6 +353,8 @@ public class MethodGen implements CGConst {
private void _finish() throws IOException {
if(size == FINISHED) return;
+ cp.stable();
+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutput o = new DataOutputStream(baos);
@@ -365,39 +379,59 @@ public class MethodGen implements CGConst {
}
switch(op) {
+ // Speical caculations
case GOTO:
- case JSR:
- p += 3;
- break;
+ case JSR: {
+ int arg = ((Integer)this.arg[i]).intValue();
+ if(arg < i && p - maxpc[arg] <= 32768) p += 3;
+ else p += 5;
+ continue;
+ }
case NOP:
if(EMIT_NOPS) p++;
- break;
+ continue;
case LOOKUPSWITCH:
case TABLESWITCH: {
SI si = (SI) arg[i];
Object[] targets = si.targets;
for(j=0;j 255) {
+ this.op[i] = WIDE;
+ this.arg[i] = new Wide(op,arg);
+ }
+ break;
+ }
+ case IINC: {
+ Pair pair = (Pair) this.arg[i];
+ if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
+ this.op[i] = WIDE;
+ this.arg[i] = new Wide(IINC,pair.i1,pair.i2);
+ }
break;
}
case LDC:
j = ((CPGen.Ent)arg[i]).getIndex();
if(j >= 256) this.op[i] = op = LDC_W;
- // fall through
- default:
- if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
- p += 1 + j;
break;
+ default:
}
+ if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
+ p += 1 + j;
}
// Pass2 - Widen instructions if they can possibly be too short
@@ -432,6 +466,9 @@ public class MethodGen implements CGConst {
else p += 4 + si.size() * 4 * 2; // count, key,val * targets
break;
}
+ case WIDE:
+ p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
+ break;
default: {
int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
if(l == 7) throw new Error("shouldn't be here");
@@ -439,7 +476,6 @@ public class MethodGen implements CGConst {
}
}
}
-
int codeSize = p;
if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
@@ -453,8 +489,7 @@ public class MethodGen implements CGConst {
byte op = this.op[i];
int opdata = OP_DATA[op&0xff];
if(op == NOP && !EMIT_NOPS) continue;
-
- o.writeByte(op&0xff);
+ o.writeByte(op);
int argLength = opdata & OP_ARG_LENGTH_MASK;
if(argLength == 0) continue; // skip if no args
@@ -491,8 +526,13 @@ public class MethodGen implements CGConst {
}
break;
}
- case WIDE:
- throw new Error("WIDE instruction not yet supported");
+ case WIDE: {
+ Wide wide = (Wide) arg;
+ o.writeByte(wide.op);
+ o.writeShort(wide.varNum);
+ if(wide.op == IINC) o.writeShort(wide.n);
+ break;
+ }
default:
if((opdata & OP_BRANCH_FLAG) != 0) {