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) {