1 package org.ibex.classgen;
6 * a highly streamlined SSA-form intermediate representation of a
7 * sequence of JVM instructions; all stack manipulation is factored
10 public class JSSA extends MethodGen implements CGConst {
12 // Constructor //////////////////////////////////////////////////////////////////////////////
14 public JSSA(Type.Class c, DataInput in, ConstantPool cp) throws IOException {
16 local = new Expr[maxLocals];
17 stack = new Expr[maxStack];
20 local[n++] = new Argument("this",method.getDeclaringClass());
21 for(int i=0;i<this.method.getNumArgs(); i++)
22 local[n++] = new Argument("arg"+i, this.method.getArgType(i));
23 for(int i=0; i<size(); i++) {
25 Object arg = getArg(i);
27 Object o = addOp(op, arg);
32 } catch(RuntimeException e) {
33 System.err.println("Had a problem at PC: " + i + " of " + method);
35 throw new IOException("invalid class file");
40 private Object[] ops = new Object[65535];
41 private int[] ofs = new int[65535];
42 private int numOps = 0;
44 // Instance Data; used ONLY during constructor; then thrown away /////////////////////////////////////////////////
46 /** this models the JVM locals; it is only used for unwinding stack-ops into an SSA-tree, then thrown away */
47 private final Expr[] local;
49 /** this models the JVM stack; it is only used for unwinding stack-ops into an SSA-tree, then thrown away */
50 private final Expr[] stack;
52 /** JVM stack pointer */
55 private Expr push(Expr e) {
56 if (sp == stack.length) {
57 for(int i=0;i<stack.length;i++) System.err.println("Stack " + i + ": " + stack[i]);
58 throw new IllegalStateException("stack overflow (" + stack.length + ")");
60 if (e.getType() == Type.VOID) throw new IllegalArgumentException("can't push a void");
61 return stack[sp++] = e;
64 if (sp == 0) throw new IllegalStateException("stack underflow");
68 private Op seqPush(Expr e) {
74 // SSA-node classes /////////////////////////////////////////////////////////////////////////////////////////
76 public final Expr VOID_EXPR = new Expr() {
77 public Type getType() { return Type.VOID; }
80 /** an purely imperative operation which does not generate data */
81 public abstract class Op {
82 //public abstract Op[] predecessors(); // not implemented yet
83 //public abstract Op[] successors(); // not implemented yet
84 public String toString() { return name(); }
86 String name = this.getClass().getName();
87 if (name.indexOf('$') != -1) name = name.substring(name.lastIndexOf('$')+1);
88 if (name.indexOf('.') != -1) name = name.substring(name.lastIndexOf('.')+1);
93 /** A sequence point. expr is evaluated for side effects at this point, this does not generate data
94 Expressions that haven't been evaluated with Seq are evaluated when they are first encountered
96 public class Seq extends Op {
97 private final Expr expr;
98 public String toString() { return expr.toString(); }
99 public Seq(Expr expr) { this.expr = expr; }
102 /** an operation which generates data */
103 public abstract class Expr extends Op {
104 //public abstract Expr[] contributors(); // not implemented yet
105 //public abstract Expr[] dependents(); // not implemented yet
107 /** every JSSA.Expr either remembers its type _OR_ knows how to figure it out (the latter is preferred to eliminate
108 * redundant information that could possibly "disagree" with itself -- this happened a LOT in Soot) */
109 public abstract Type getType();
111 public final String toString() { return exprToString(this); }
112 public String _toString() { return super.toString(); } // Adam is going to hate me for this
116 * A "nondeterministic merge" -- for example when the first instruction in a loop reads from a local which could have been
117 * written to either by some instruction at the end of the previous iteration of the loop or by some instruction before
118 * the loop (on the first iteration).
120 public class Phi extends Expr {
121 private final Expr[] inputs;
122 public Phi(Expr[] inputs) {
123 this.inputs = new Expr[inputs.length];
124 System.arraycopy(inputs, 0, this.inputs, 0, inputs.length);
126 public Type getType() {
128 Type t = inputs[0].getType();
130 // FIXME: actually this should check type-unifiability... fe, the "type of null" unifies with any Type.Ref
131 for(int i=1; i<inputs.length; i++)
132 if (inputs[i].getType() != t)
133 throw new Error("Phi node with disagreeing types! Crisis!");
138 public class Argument extends Expr {
139 public final String name;
141 public Argument(String name, Type t) { this.name = name; this.t = t; }
142 public String _toString() { return name; }
143 public Type getType() { return t; }
147 public class Not extends Expr {
150 if (e.getType() != Type.BOOLEAN) throw new IllegalArgumentException("not needs a boolean expression");
153 public Type getType() { return Type.BOOLEAN; }
154 public String _toString() { return "!(" + e + ")"; }
157 public class Neg extends Expr {
160 if (!e.getType().isPrimitive()) throw new IllegalArgumentException("can only negate a primitive");
163 public Type getType() { return e.getType(); }
164 public String _toString() { return "- (" + e + ")"; }
167 // Binary Operations //////////////////////////////////////////////////////////////////////////////
169 public abstract class BinExpr extends Expr {
170 public final Expr e1;
171 public final Expr e2;
172 private final String show;
173 public BinExpr(Expr e1, Expr e2, String show) { this.e1 = e1; this.e2 = e2; this.show = show; }
174 public String _toString() {
175 // FEATURE: should we be doing some precedence stuff here? probably no worth it for debugging output
176 return "(" + e1 + show + e2 + ")";
180 public class Comparison extends BinExpr {
181 public Comparison(Expr e1, Expr e2, String show) { super(e1, e2, show); }
182 public Type getType() { return Type.BOOLEAN; }
185 public class Eq extends Comparison {
186 public Eq(Expr e1, Expr e2) {
188 if (e1.getType().isPrimitive() != e2.getType().isPrimitive())
189 throw new IllegalArgumentException("type mismatch");
190 if (e1.getType().isPrimitive() && e1.getType() != e2.getType())
191 throw new IllegalArgumentException("type mismatch");
192 // FEATURE: Check if we can compare these classes
197 public class PrimitiveComparison extends Comparison {
198 public PrimitiveComparison(Expr e1, Expr e2, String show) {
200 if (!e1.getType().isPrimitive() || e1.getType() != e2.getType()) throw new IllegalArgumentException("type mismatch");
204 public class Gt extends PrimitiveComparison { public Gt(Expr e1, Expr e2) { super(e1, e2, ">"); } }
205 public class Lt extends PrimitiveComparison { public Lt(Expr e1, Expr e2) { super(e1, e2, "<"); } }
206 public class Ge extends PrimitiveComparison { public Ge(Expr e1, Expr e2) { super(e1, e2, ">="); } }
207 public class Le extends PrimitiveComparison { public Le(Expr e1, Expr e2) { super(e1, e2, "<="); } }
209 // Math Operations //////////////////////////////////////////////////////////////////////////////
211 public class BinMath extends BinExpr {
212 public BinMath(Expr e1, Expr e2, String show) {
214 if (e1.getType() != e2.getType()) throw new IllegalArgumentException("types disagree");
216 public Type getType() { return e1.getType(); }
219 public class Add extends BinMath { public Add(Expr e, Expr e2) { super(e, e2, "+"); } }
220 public class Sub extends BinMath { public Sub(Expr e, Expr e2) { super(e, e2, "-"); } }
221 public class Mul extends BinMath { public Mul(Expr e, Expr e2) { super(e, e2, "*"); } }
222 public class Rem extends BinMath { public Rem(Expr e, Expr e2) { super(e, e2, "%"); } }
223 public class Div extends BinMath { public Div(Expr e, Expr e2) { super(e, e2, "/"); } }
224 public class And extends BinMath { public And(Expr e, Expr e2) { super(e, e2, "&"); } }
225 public class Or extends BinMath { public Or(Expr e, Expr e2) { super(e, e2, "|"); } }
226 public class Xor extends BinMath { public Xor(Expr e, Expr e2) { super(e, e2, "^"); } }
228 public class BitShiftExpr extends BinExpr {
229 public BitShiftExpr(Expr e1, Expr e2, String show) {
231 Type t = e1.getType();
232 if (t != Type.INT && t != Type.LONG) throw new IllegalArgumentException("type mismatch");
233 if (e2.getType() != Type.INT) throw new IllegalArgumentException("type mismatch");
235 public Type getType() { return e1.getType(); }
237 public class Shl extends BitShiftExpr { public Shl(Expr e, Expr e2) { super(e, e2, "<<"); } }
238 public class Shr extends BitShiftExpr { public Shr(Expr e, Expr e2) { super(e, e2, ">>"); } }
239 public class Ushr extends BitShiftExpr { public Ushr(Expr e, Expr e2) { super(e, e2, ">>>"); } }
241 // Other operations //////////////////////////////////////////////////////////////////////////////
243 public class Cast extends Expr {
246 public Cast(Expr e, Type t) {
247 if (e.getType().isRef() != t.isRef()) throw new IllegalArgumentException("invalid cast");
248 // FEATURE: Check that one is a subclass of the other if it is a ref
252 public Type getType() { return t; }
255 public class InstanceOf extends Expr {
258 public InstanceOf(Expr e, Type.Ref t) {
259 if (!e.getType().isRef()) throw new IllegalArgumentException("can't do an instanceof check on a non-ref");
263 public Type getType() { return Type.BOOLEAN; }
266 public class Throw extends Op {
268 public Throw(Expr e) {
269 if (!e.getType().isRef()) throw new IllegalArgumentException("can't throw a non ref");
270 // FEATURE: CHeck that it is a subclass of Throwable
275 public class Branch extends Op {
276 public Branch(Expr condition, Object destination) { }
277 public Branch(Label destination) { }
278 public Branch(MethodGen.Switch s) { }
281 public class Goto extends Branch { }
282 public class RET extends Branch { }
283 public class JSR extends Branch { public JSR(Label l) { super(l); } }
284 public class If extends Branch { }
286 /** represents a "returnaddr" pushed onto the stack */
287 public class Label extends Expr {
289 public Type getType() { throw new Error("attempted to call getType() on a Label"); }
290 public Label(Op op) { this.op = op; }
291 public Label(int i) { this.op = null; /* FIXME */ }
294 public class New extends Expr {
295 public final Type.Class t;
296 public Type getType() { return t; }
297 public New(Type.Class t) { this.t = t; }
298 public String _toString() { return "new " + t + "()"; }
301 public class NewArray extends Expr {
302 public final Type.Array t;
303 public final Expr[] dims;
304 public NewArray(Type.Array t, Expr[] dims) { this.t = t; this.dims = dims; }
305 public NewArray(Type.Array t, Expr dim) { this(t,new Expr[]{dim}); }
306 public Type getType() { return t; }
307 public String _toString() {
310 while(base.isArray()) {
312 base = base.asArray().getElementType();
314 StringBuffer sb = new StringBuffer("new " + base);
315 for(int i=0;i<totalDims;i++)
316 sb.append("[" + (i < dims.length ? dims[i].toString() : "") + "]");
317 return sb.toString();
321 public class Return extends Op {
323 public Return() { this(VOID_EXPR); }
324 public Return(Expr e) {
326 if (Type.unify(method.getReturnType(),e.getType()) != method.getReturnType())
327 throw new IllegalArgumentException("type mismatch");
329 public String toString() { return e.getType() == Type.VOID ? "return" : ("return "+e.toString()); }
332 /** GETFIELD and GETSTATIC */
333 public class Get extends Expr {
334 final Type.Class.Field f;
336 public Type getType() { return f.getType(); }
337 public Get(Type.Class.Field f) { this(f, null); }
338 public Get(Type.Class.Field f, Expr e) { this.f = f; this.e = e; }
339 public String _toString() {
343 : f.getDeclaringClass() == JSSA.this.method.getDeclaringClass()
349 /** PUTFIELD and PUTSTATIC */
350 public class Put extends Op {
351 final Type.Class.Field f;
354 public Put(Type.Class.Field f, Expr v) { this(f, v, null); }
355 public Put(Type.Class.Field f, Expr v, Expr e) { this.f = f; this.v = v; this.e = e; }
356 public String toString() {
360 : f.getDeclaringClass() == JSSA.this.method.getDeclaringClass()
362 : f.toString()) + " = " + v;
366 public class ArrayPut extends Op {
368 public ArrayPut(Expr v, Expr i, Expr e) { this.e = e; this.i = i; this.v = v; }
369 public String toString() { return e + "[" + i + "] := " + v; }
372 public class ArrayGet extends Expr {
374 public ArrayGet(Expr i, Expr e) { this.e = e; this.i = i; }
375 public Type getType() { return e.getType().asArray().getElementType(); }
376 public String _toString() { return e + "[" + i + "]"; }
379 public class ArrayLength extends Expr {
381 public ArrayLength(Expr e) { this.e = e; }
382 public Type getType() { return Type.INT; }
385 public abstract class Invoke extends Expr {
386 public final Expr[] arguments;
387 public final Type.Class.Method method;
388 protected Invoke(Type.Class.Method m, Expr[] a) { this.arguments = a; this.method = m; }
390 public Type getType() { return method.getReturnType(); }
391 protected void args(StringBuffer sb) {
393 for(int i=0; i<arguments.length; i++) {
394 if (i>0) sb.append(", ");
395 sb.append(arguments[i]+"");
400 public String _toString() {
401 StringBuffer sb = new StringBuffer();
402 sb.append(method.getDeclaringClass() == JSSA.this.method.getDeclaringClass()
404 : (method.getDeclaringClass() + "." + method.name));
406 return sb.toString();
409 public class InvokeStatic extends Invoke { public InvokeStatic(Type.Class.Method m, Expr[] a) { super(m,a); } }
410 public class InvokeSpecial extends InvokeVirtual {
411 public InvokeSpecial(Type.Class.Method m, Expr[] a, Expr e) { super(m,a,e); }
412 public String _toString() { return _toString(method.name.equals("<init>") ? method.getDeclaringClass().getName() : method.name); }
414 public class InvokeInterface extends InvokeVirtual{public InvokeInterface(Type.Class.Method m, Expr[] a, Expr e){super(m,a,e);}}
415 public class InvokeVirtual extends Invoke {
416 public final Expr instance;
417 public InvokeVirtual(Type.Class.Method m, Expr[] a, Expr e) { super(m, a); instance = e; }
418 public String _toString() { return _toString(method.name); }
419 protected String _toString(String name) {
420 StringBuffer sb = new StringBuffer();
421 sb.append(instance+".");
424 return sb.toString();
428 public class Constant extends Expr {
429 private final Object o;
430 public Constant(int i) { this(new Integer(i)); }
431 public Constant(Object o) { this.o = o; }
432 public String _toString() { return o == null ? "null" : o instanceof String ? "\"" + o + "\"" : o.toString(); }
433 public Type getType() {
434 if (o == null) return Type.NULL;
435 if (o instanceof Byte) return Type.BYTE;
436 if (o instanceof Short) return Type.SHORT;
437 if (o instanceof Character) return Type.CHAR;
438 if (o instanceof Boolean) return Type.BOOLEAN;
439 if (o instanceof Long) return Type.LONG;
440 if (o instanceof Double) return Type.DOUBLE;
441 if (o instanceof Float) return Type.FLOAT;
442 if (o instanceof Integer) return Type.INT;
443 if (o instanceof String) return Type.STRING;
444 throw new IllegalStateException("unknown constant type");
449 // Implementation //////////////////////////////////////////////////////////////////////////////
451 private Object addOp(int op, Object arg) {
455 MethodGen.Wide w = (MethodGen.Wide)arg;
462 MethodGen.Pair p = (MethodGen.Pair)arg;
469 case NOP: return null;
471 // Stack manipulations //////////////////////////////////////////////////////////////////////////////
473 case ACONST_NULL: push(new Constant(null)); return null;
474 case ICONST_M1: push(new Constant(-1)); return null;
475 case ICONST_0: case LCONST_0: case FCONST_0: case DCONST_0: push(new Constant(0)); return null;
476 case ICONST_1: case LCONST_1: case FCONST_1: case DCONST_1: push(new Constant(1)); return null;
477 case ICONST_2: case FCONST_2: push(new Constant(2)); return null;
478 case ICONST_3: push(new Constant(3)); return null;
479 case ICONST_4: push(new Constant(4)); return null;
480 case ICONST_5: push(new Constant(5)); return null;
481 case ILOAD: case LLOAD: case FLOAD: case DLOAD: case ALOAD: push(local[i1]); return null;
482 case ILOAD_0: case LLOAD_0: case FLOAD_0: case DLOAD_0: case ALOAD_0: push(local[0]); return null;
483 case ILOAD_1: case LLOAD_1: case FLOAD_1: case DLOAD_1: case ALOAD_1: push(local[1]); return null;
484 case ALOAD_2: case DLOAD_2: case FLOAD_2: case LLOAD_2: case ILOAD_2: push(local[2]); return null;
485 case ILOAD_3: case LLOAD_3: case FLOAD_3: case DLOAD_3: case ALOAD_3: push(local[3]); return null;
486 case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: local[i1] = pop(); return null;
487 case ISTORE_0: case LSTORE_0: case FSTORE_0: case DSTORE_0: case ASTORE_0: local[0] = pop(); return null;
488 case ISTORE_1: case LSTORE_1: case FSTORE_1: case DSTORE_1: case ASTORE_1: local[1] = pop(); return null;
489 case ASTORE_2: case DSTORE_2: case FSTORE_2: case LSTORE_2: case ISTORE_2: local[2] = pop(); return null;
490 case ISTORE_3: case LSTORE_3: case FSTORE_3: case DSTORE_3: case ASTORE_3: local[3] = pop(); return null;
491 case POP: pop(); return null;
492 case POP2: pop(); pop(); return null;
493 case DUP: push(stack[sp-1]); return null;
494 case DUP2: push(stack[sp-2]); push(stack[sp-2]); return null;
496 // Conversions //////////////////////////////////////////////////////////////////////////////
498 // coercions are added as-needed when converting from JSSA back to bytecode, so we can
499 // simply discard them here (assuming the bytecode we're reading in was valid in the first place)
501 case I2L: case F2L: case D2L: push(new Cast(pop(), Type.LONG)); return null;
502 case I2F: case L2F: case D2F: push(new Cast(pop(), Type.FLOAT)); return null;
503 case I2D: case L2D: case F2D: push(new Cast(pop(), Type.DOUBLE)); return null;
504 case L2I: case F2I: case D2I: push(new Cast(pop(), Type.INT)); return null;
505 case I2B: push(new Cast(pop(), Type.BYTE)); return null;
506 case I2C: push(new Cast(pop(), Type.CHAR)); return null;
507 case I2S: push(new Cast(pop(), Type.SHORT)); return null;
508 case SWAP: { Expr e1 = pop(), e2 = pop(); push(e2); push(e1); return null; }
510 // Math //////////////////////////////////////////////////////////////////////////////
512 case IADD: case LADD: case FADD: case DADD: push(new Add(pop(), pop())); return null;
513 case ISUB: case LSUB: case FSUB: case DSUB: push(new Sub(pop(), pop())); return null;
514 case IMUL: case LMUL: case FMUL: case DMUL: push(new Mul(pop(), pop())); return null;
515 case IREM: case LREM: case FREM: case DREM: push(new Rem(pop(), pop())); return null;
516 //case INEG: case LNEG: case FNEG: case DNEG: push(new Neg(pop())); return null;
517 case IDIV: case LDIV: case FDIV: case DDIV: push(new Div(pop(), pop())); return null;
518 case ISHL: case LSHL: push(new Shl(pop(), pop())); return null;
519 case ISHR: case LSHR: push(new Shr(pop(), pop())); return null;
520 case IUSHR: case LUSHR: push(new Ushr(pop(), pop())); return null;
521 case IAND: case LAND: push(new And(pop(), pop())); return null;
522 case IOR: case LOR: push(new Or(pop(), pop())); return null;
523 case IXOR: case LXOR: push(new Xor(pop(), pop())); return null;
524 case IINC: return local[i1] = new Add(local[i1], new Constant(i2));
526 // Control and branching //////////////////////////////////////////////////////////////////////////////
528 case IFNULL: return new Branch(new Eq(pop(), new Constant(null)), new Label(i1));
529 case IFNONNULL: return new Branch(new Not(new Eq(pop(),new Constant(null))),new Label(i1));
530 case IFEQ: return new Branch( new Eq(new Constant(0), pop()), arg);
531 case IFNE: return new Branch(new Not(new Eq(new Constant(0), pop())), arg);
532 case IFLT: return new Branch( new Lt(new Constant(0), pop()), arg);
533 case IFGE: return new Branch(new Not(new Lt(new Constant(0), pop())), arg);
534 case IFGT: return new Branch( new Gt(new Constant(0), pop()), arg);
535 case IFLE: return new Branch(new Not(new Gt(new Constant(0), pop())), arg);
536 case IF_ICMPEQ: return new Branch( new Eq(pop(), pop()), arg);
537 case IF_ICMPNE: return new Branch(new Not(new Eq(pop(), pop())), arg);
538 case IF_ICMPLT: return new Branch( new Lt(pop(), pop()), arg);
539 case IF_ICMPGE: return new Branch(new Not(new Lt(pop(), pop())), arg);
540 case IF_ICMPGT: return new Branch( new Gt(pop(), pop()), arg);
541 case IF_ICMPLE: return new Branch(new Not(new Gt(pop(), pop())), arg);
542 case IF_ACMPEQ: return new Branch( new Eq(pop(), pop()), arg);
543 case IF_ACMPNE: return new Branch(new Not(new Eq(pop(), pop())), arg);
544 case ATHROW: return new Throw(pop());
545 case GOTO: return new Branch(new Label(i1));
546 case JSR: return new JSR(new Label(i1));
547 case RET: return new RET();
548 case RETURN: return new Return();
549 case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN:
550 return new Return(pop());
552 // Array manipulations //////////////////////////////////////////////////////////////////////////////
554 case IALOAD: case LALOAD: case FALOAD: case DALOAD: case AALOAD:
555 case BALOAD: case CALOAD: case SALOAD:
556 return seqPush(new ArrayGet(pop(), pop()));
557 case IASTORE: case LASTORE: case FASTORE: case DASTORE: case AASTORE:
558 case BASTORE: case CASTORE: case SASTORE:
559 return new ArrayPut(pop(), pop(), pop());
561 // Invocation //////////////////////////////////////////////////////////////////////////////
563 case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case INVOKEINTERFACE: {
564 Type.Class.Method method = (Type.Class.Method)arg;
565 Expr args[] = new Expr[method.getNumArgs()];
566 for(int i=0; i<args.length; i++) args[args.length-i-1] = pop();
569 case INVOKEVIRTUAL: ret = new InvokeVirtual(method, args, pop()); break;
570 case INVOKEINTERFACE: ret = new InvokeInterface(method, args, pop()); break;
571 case INVOKESPECIAL: ret = new InvokeSpecial(method, args, pop()); break;
572 case INVOKESTATIC: ret = new InvokeStatic(method, args); break;
573 default: throw new Error("should never happen");
575 if (ret.getType() != Type.VOID) push(ret);
579 // Field Access //////////////////////////////////////////////////////////////////////////////
581 case GETSTATIC: return seqPush(new Get((Type.Class.Field)arg, null));
582 case PUTSTATIC: return new Put((Type.Class.Field)arg, pop(), null);
583 case GETFIELD: return seqPush(new Get((Type.Class.Field)arg, pop()));
584 case PUTFIELD: return new Put((Type.Class.Field)arg, pop(), pop());
586 // Allocation //////////////////////////////////////////////////////////////////////////////
588 case NEW: push(new New((Type.Class)arg)); return null;
591 switch(((Integer)arg).intValue()) {
592 case 4: base = Type.BOOLEAN; break;
593 case 5: base = Type.CHAR; break;
594 case 6: base = Type.FLOAT; break;
595 case 7: base = Type.DOUBLE; break;
596 case 8: base = Type.BYTE; break;
597 case 9: base = Type.SHORT; break;
598 case 10: base = Type.INT; break;
599 case 11: base = Type.LONG; break;
600 default: throw new IllegalStateException("invalid array type");
602 return seqPush(new NewArray(base.makeArray(),pop()));
604 case ANEWARRAY: push(new NewArray(((Type.Ref)arg).makeArray(), pop())); return null;
605 case MULTIANEWARRAY: {
606 MethodGen.MultiANewArray mana = (MethodGen.MultiANewArray) arg;
607 Expr[] dims = new Expr[mana.dims];
608 for(int i=0;i<dims.length;i++) dims[i] = pop();
609 return seqPush(new NewArray(mana.type, dims));
611 case ARRAYLENGTH: return seqPush(new ArrayLength(pop()));
613 // Runtime Type information //////////////////////////////////////////////////////////////////////////////
615 case CHECKCAST: return seqPush(new Cast(pop(), (Type.Ref)arg));
616 case INSTANCEOF: push(new InstanceOf(pop(), (Type.Ref)arg)); return null;
618 case LDC: case LDC_W: case LDC2_W: push(new Constant(arg)); return null;
620 case BIPUSH: push(new Constant((Integer)arg)); return null;
621 case SIPUSH: push(new Constant((Integer)arg)); return null;
623 case TABLESWITCH: return new Branch((MethodGen.Switch)arg);
624 case LOOKUPSWITCH: return new Branch((MethodGen.Switch)arg);
627 case MONITORENTER: Op.monitorEnter(pop());
628 case MONITOREXIT: Op.monitorExit(pop());
631 case DUP_X1: throw new Error("unimplemented");
632 case DUP_X2: throw new Error("unimplemented");
633 case DUP2_X1: throw new Error("unimplemented");
634 case DUP2_X2: throw new Error("unimplemented");
635 case LCMP: throw new Error("unimplemented");
636 case FCMPL: throw new Error("unimplemented");
637 case FCMPG: throw new Error("unimplemented");
638 case DCMPL: throw new Error("unimplemented");
639 case DCMPG: throw new Error("unimplemented");
640 case GOTO_W: throw new Error("unimplemented");
641 case JSR_W: throw new Error("unimplemented");
642 default: throw new Error("unhandled");
647 public void debugBodyToString(StringBuffer sb) {
648 StringBuffer sb0 = new StringBuffer();
649 super.debugBodyToString(sb0);
650 StringTokenizer st = new StringTokenizer(sb0.toString(), "\n");
651 String[] lines = new String[st.countTokens()];
652 for(int i=0; i<lines.length; i++) lines[i] = st.nextToken();
653 for(int j=0; j<ofs[0]; j++) {
654 String s = " /* " + lines[j].trim();
655 while(s.length() < 50) s += " ";
661 bindingMap = new IdentityHashMap();
664 for(int i=0; i<numOps; i++) {
665 String s = " /* " + lines[ofs[i]].trim();
666 while(s.length() < 50) s += " ";
668 s += ops[i].toString();
671 for(int j=ofs[i]+1; j<(i==numOps-1?size():ofs[i+1]); j++) {
672 s = " /* " + lines[j].trim();
673 while(s.length() < 50) s += " ";
681 private Map bindingMap;
683 String exprToString(Expr e) {
684 if (e instanceof Constant) return e._toString();
685 String s = (String)bindingMap.get(e);
686 if (s != null) return s;
688 if (e.getType() == Type.VOID) return e._toString();
689 else if (e.getType() == Type.DOUBLE || e.getType() == Type.FLOAT) prefix = "f";
690 else if (e.getType().isPrimitive()) prefix = "i";
691 else if (e.getType().isArray()) prefix = "a";
693 s = prefix + (nextVar++);
695 return "(" + s + " = " + e._toString() + ")";
698 public static void main(String[] args) throws Exception {
699 InputStream is = Class.forName(args[0]).getClassLoader().getResourceAsStream(args[0].replace('.', '/')+".class");
700 System.out.println(new ClassFile(new DataInputStream(is), true).toString());