0001: // Copyright (c) 1997, 1998, 1999, 2001 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.bytecode;
0005:
0006: import java.io.*;
0007:
0008: /**
0009: * Represents the contents of a standard "Code" attribute.
0010: * <p>
0011: * Most of the actual methods that generate bytecode operation
0012: * are in this class (typically with names starting with <code>emit</code>),
0013: * though there are also some in <code>Method</code>.
0014: * <p>
0015: * Note that a <code>CodeAttr</code> is an <code>Attribute</code>
0016: * of a <code>Method</code>, and can in turn contain other
0017: * <code>Attribute</code>s, such as a <code>LineNumbersAttr</code>.
0018: *
0019: * @author Per Bothner
0020: */
0021:
0022: public class CodeAttr extends Attribute implements AttrContainer {
0023: Attribute attributes;
0024:
0025: public final Attribute getAttributes() {
0026: return attributes;
0027: }
0028:
0029: public final void setAttributes(Attribute attributes) {
0030: this .attributes = attributes;
0031: }
0032:
0033: LineNumbersAttr lines;
0034: public LocalVarsAttr locals;
0035:
0036: // In hindsight, maintaining stack_types is more hassle than it is worth.
0037: // Instead, better to just keep track of SP, which should catch most
0038: // stack errors, while being more general and less hassle. FIXME.
0039: Type[] stack_types;
0040:
0041: public int SP; // Current stack size (in "words")
0042: private int max_stack;
0043: private int max_locals;
0044: int PC;
0045: // readPC (which is <= PC) is a bound on locations that have been
0046: // saved into labels or otherwise externally seen.
0047: // Hence, we cannot re-arrange code upto readPC, but we can
0048: // rearrange code between readPC and PC.
0049: int readPC;
0050: byte[] code;
0051:
0052: // The PC of the previous instruction.
0053: int previousPC;
0054:
0055: /* The exception handler table, as a vector of quadruples
0056: (start_pc, end_pc, handler_pc, catch_type).
0057: Only the first exception_table_length quadrules are defined. */
0058: short[] exception_table;
0059:
0060: /* The number of (defined) exception handlers (i.e. quadruples)
0061: in exception_table. */
0062: int exception_table_length;
0063:
0064: /* A chain of labels. Unsorted, except that the Label with
0065: the lowest element in fixups must be the first one. */
0066: Label labels;
0067:
0068: CodeFragment fragments;
0069:
0070: /** The stack of currently active conditionals. */
0071: IfState if_stack;
0072:
0073: /** The stack of currently active try statements. */
0074: TryState try_stack;
0075:
0076: public final TryState getTryStack() {
0077: return try_stack;
0078: }
0079:
0080: public final Method getMethod() {
0081: return (Method) getContainer();
0082: }
0083:
0084: public final int getPC() {
0085: return PC;
0086: }
0087:
0088: public final ConstantPool getConstants() {
0089: return getMethod().classfile.constants;
0090: }
0091:
0092: /* True if we cannot fall through to bytes[PC] -
0093: the previous instruction was an uncondition control transfer. */
0094: boolean unreachable_here;
0095:
0096: /** True if control could reach here. */
0097: public boolean reachableHere() {
0098: return !unreachable_here;
0099: }
0100:
0101: public final void setReachable(boolean val) {
0102: unreachable_here = !val;
0103: }
0104:
0105: public final void setUnreachable() {
0106: unreachable_here = true;
0107: }
0108:
0109: /** Get the maximum number of words on the operand stack in this method. */
0110: public int getMaxStack() {
0111: return max_stack;
0112: }
0113:
0114: /** Get the maximum number of local variable words in this method. */
0115: public int getMaxLocals() {
0116: return max_locals;
0117: }
0118:
0119: /** Set the maximum number of words on the operand stack in this method. */
0120: public void setMaxStack(int n) {
0121: max_stack = n;
0122: }
0123:
0124: /** Set the maximum number of local variable words in this method. */
0125: public void setMaxLocals(int n) {
0126: max_locals = n;
0127: }
0128:
0129: /** Get the code (instruction bytes) of this method.
0130: * Does not make a copy. */
0131: public byte[] getCode() {
0132: return code;
0133: }
0134:
0135: /** Set the code (instruction bytes) of this method.
0136: * @param code the code bytes (which are not copied).
0137: * Implicitly calls setCodeLength(code.length). */
0138: public void setCode(byte[] code) {
0139: this .code = code;
0140: this .PC = code.length;
0141: readPC = PC;
0142: }
0143:
0144: /** Set the length the the code (instruction bytes) of this method.
0145: * That is the number of current used bytes in getCode().
0146: * (Any remaing bytes provide for future growth.) */
0147: public void setCodeLength(int len) {
0148: PC = len;
0149: readPC = len;
0150: }
0151:
0152: /** Set the current lengthof the code (instruction bytes) of this method. */
0153: public int getCodeLength() {
0154: readPC = PC;
0155: return PC;
0156: }
0157:
0158: public CodeAttr(Method meth) {
0159: super ("Code");
0160: addToFrontOf(meth);
0161: meth.code = this ;
0162: }
0163:
0164: public final void reserve(int bytes) {
0165: previousPC = PC;
0166: if (code == null)
0167: code = new byte[100 + bytes];
0168: else if (PC + bytes > code.length) {
0169: byte[] new_code = new byte[2 * code.length + bytes];
0170: System.arraycopy(code, 0, new_code, 0, PC);
0171: code = new_code;
0172: }
0173:
0174: while (labels != null && labels.fixups != null) {
0175: int oldest_fixup = labels.fixups[0];
0176: int threshold = unreachable_here ? 30000 : 32000;
0177: if (PC + bytes - oldest_fixup > threshold)
0178: labels.emit_spring(this );
0179: else
0180: break;
0181: }
0182: }
0183:
0184: /**
0185: * Write an 8-bit byte to the current code-stream.
0186: * @param i the byte to write
0187: */
0188: public final void put1(int i) {
0189: code[PC++] = (byte) i;
0190: unreachable_here = false;
0191: }
0192:
0193: /**
0194: * Write a 16-bit short to the current code-stream
0195: * @param i the value to write
0196: */
0197: public final void put2(int i) {
0198: code[PC++] = (byte) (i >> 8);
0199: code[PC++] = (byte) (i);
0200: unreachable_here = false;
0201: }
0202:
0203: /**
0204: * Write a 32-bit int to the current code-stream
0205: * @param i the value to write
0206: */
0207: public final void put4(int i) {
0208: code[PC++] = (byte) (i >> 24);
0209: code[PC++] = (byte) (i >> 16);
0210: code[PC++] = (byte) (i >> 8);
0211:
0212: code[PC++] = (byte) (i);
0213: unreachable_here = false;
0214: }
0215:
0216: public final void putIndex2(CpoolEntry cnst) {
0217: put2(cnst.index);
0218: }
0219:
0220: public final void putLineNumber(String file, int linenumber) {
0221: if (lines == null)
0222: lines = new LineNumbersAttr(this );
0223: readPC = PC;
0224: lines.put(file, linenumber, PC);
0225: }
0226:
0227: public final void pushType(Type type) {
0228: if (type.size == 0)
0229: throw new Error("pushing void type onto stack");
0230: if (stack_types == null)
0231: stack_types = new Type[20];
0232: else if (SP + 1 >= stack_types.length) {
0233: Type[] new_array = new Type[2 * stack_types.length];
0234: System.arraycopy(stack_types, 0, new_array, 0, SP);
0235: stack_types = new_array;
0236: }
0237: if (type.size == 8)
0238: stack_types[SP++] = Type.void_type;
0239: stack_types[SP++] = type;
0240: if (SP > max_stack)
0241: max_stack = SP;
0242: }
0243:
0244: public final Type popType() {
0245: if (SP <= 0)
0246: throw new Error("popType called with empty stack in "
0247: + getMethod());
0248: Type type = stack_types[--SP];
0249: if (type.size == 8)
0250: if (!popType().isVoid())
0251: throw new Error("missing void type on stack");
0252: return type;
0253: }
0254:
0255: public final Type topType() {
0256: if (SP <= 0)
0257: //throw new Error("popType called with empty stack "+getMethod());
0258: return null;
0259: return stack_types[SP - 1];
0260: }
0261:
0262: /** Compile code to pop values off the stack (and ignore them).
0263: * @param nvalues the number of values (not words) to pop
0264: */
0265: public void emitPop(int nvalues) {
0266: for (; nvalues > 0; --nvalues) {
0267: reserve(1);
0268: Type type = popType();
0269: if (type.size > 4)
0270: put1(88); // pop2
0271: else if (nvalues > 1) { // optimization: can we pop 2 4-byte words using a pop2
0272: Type type2 = popType();
0273: if (type2.size > 4) {
0274: put1(87); // pop
0275: reserve(1);
0276: }
0277: put1(88); // pop2
0278: --nvalues;
0279: } else
0280: put1(87); // pop
0281: }
0282: }
0283:
0284: public void emitSwap() {
0285: reserve(1);
0286: Type type1 = popType();
0287: Type type2 = popType();
0288:
0289: if (type1.size > 4 || type2.size > 4) {
0290: // There is no swap instruction in the JVM for this case.
0291: // Fall back to a more convoluted way.
0292: pushType(type2);
0293: pushType(type1);
0294: emitDupX();
0295: emitPop(1);
0296: } else {
0297: pushType(type1);
0298: put1(95); // swap
0299: pushType(type2);
0300: }
0301: }
0302:
0303: /** Emit code to duplicate the top element of the stack. */
0304: public void emitDup() {
0305: reserve(1);
0306:
0307: Type type = topType();
0308: put1(type.size <= 4 ? 89 : 92); // dup or dup2
0309: pushType(type);
0310: }
0311:
0312: public void emitNop() {
0313: reserve(1);
0314: put1(0); // nop
0315: }
0316:
0317: /** Emit code to duplicate the top element of the stack
0318: and place the copy before the previous element. */
0319: public void emitDupX() {
0320: reserve(1);
0321:
0322: Type type = popType();
0323: Type skipedType = popType();
0324:
0325: if (skipedType.size <= 4)
0326: put1(type.size <= 4 ? 90 : 93); // dup_x1 or dup2_x1
0327: else
0328: put1(type.size <= 4 ? 91 : 94); // dup_x2 or dup2_x2
0329:
0330: pushType(type);
0331: pushType(skipedType);
0332: pushType(type);
0333: }
0334:
0335: /** Compile code to duplicate with offset.
0336: * @param size the size of the stack item to duplicate (1 or 2)
0337: * @param offset where to insert the result (must be 0, 1, or 2)
0338: * The new words get inserted at stack[SP-size-offset]
0339: */
0340: public void emitDup(int size, int offset) {
0341: if (size == 0)
0342: return;
0343: reserve(1);
0344: // copied1 and (optionally copied2) are the types of the duplicated words
0345: Type copied1 = popType();
0346: Type copied2 = null;
0347: if (size == 1) {
0348: if (copied1.size > 4)
0349: throw new Error("using dup for 2-word type");
0350: } else if (size != 2)
0351: throw new Error("invalid size to emitDup");
0352: else if (copied1.size <= 4) {
0353: copied2 = popType();
0354: if (copied2.size > 4)
0355: throw new Error("dup will cause invalid types on stack");
0356: }
0357:
0358: int kind;
0359: // These are the types of the words (in any) that are "skipped":
0360: Type skipped1 = null;
0361: Type skipped2 = null;
0362: if (offset == 0) {
0363: kind = size == 1 ? 89 : 92; // dup or dup2
0364: } else if (offset == 1) {
0365: kind = size == 1 ? 90 : 93; // dup_x1 or dup2_x1
0366: skipped1 = popType();
0367: if (skipped1.size > 4)
0368: throw new Error("dup will cause invalid types on stack");
0369: } else if (offset == 2) {
0370: kind = size == 1 ? 91 : 94; // dup_x2 or dup2_x2
0371: skipped1 = popType();
0372: if (skipped1.size <= 4) {
0373: skipped2 = popType();
0374: if (skipped2.size > 4)
0375: throw new Error(
0376: "dup will cause invalid types on stack");
0377: }
0378: } else
0379: throw new Error("emitDup: invalid offset");
0380:
0381: put1(kind);
0382: if (copied2 != null)
0383: pushType(copied2);
0384: pushType(copied1);
0385: if (skipped2 != null)
0386: pushType(skipped2);
0387: if (skipped1 != null)
0388: pushType(skipped1);
0389: if (copied2 != null)
0390: pushType(copied2);
0391: pushType(copied1);
0392: }
0393:
0394: /**
0395: * Compile code to duplicate the top 1 or 2 words.
0396: * @param size number of words to duplicate
0397: */
0398: public void emitDup(int size) {
0399: emitDup(size, 0);
0400: }
0401:
0402: /** Duplicate the top element of the given type. */
0403: public void emitDup(Type type) {
0404: emitDup(type.size > 4 ? 2 : 1, 0);
0405: }
0406:
0407: public void enterScope(Scope scope) {
0408: scope.setStartPC(PC);
0409: locals.enterScope(scope);
0410: }
0411:
0412: public Scope pushScope() {
0413: Scope scope = new Scope();
0414: scope.start_pc = PC;
0415: readPC = PC;
0416: if (locals == null)
0417: locals = new LocalVarsAttr(getMethod());
0418: locals.enterScope(scope);
0419: if (locals.parameter_scope == null)
0420: locals.parameter_scope = scope;
0421: return scope;
0422: }
0423:
0424: public Scope getCurrentScope() {
0425: return locals.current_scope;
0426: }
0427:
0428: /** Return the toplevel scope, corresponding to the current method. */
0429: public Scope methodScope() {
0430: Scope res = getCurrentScope();
0431: while (res.parent != null)
0432: res = res.parent;
0433: return res;
0434: }
0435:
0436: public Scope popScope() {
0437: Scope scope = locals.current_scope;
0438: locals.current_scope = scope.parent;
0439: scope.end_pc = PC;
0440: readPC = PC;
0441: for (Variable var = scope.vars; var != null; var = var.next) {
0442: if (var.isSimple() && !var.dead())
0443: var.freeLocal(this );
0444: }
0445: return scope;
0446: }
0447:
0448: /** Get the index'th parameter. */
0449: public Variable getArg(int index) {
0450: return locals.parameter_scope.getVariable(index);
0451: }
0452:
0453: /**
0454: * Search by name for a Variable
0455: * @param name name to search for
0456: * @return the Variable, or null if not found (in any scope of this Method).
0457: */
0458: public Variable lookup(String name) {
0459: Scope scope = locals.current_scope;
0460: for (; scope != null; scope = scope.parent) {
0461: Variable var = scope.lookup(name);
0462: if (var != null)
0463: return var;
0464: }
0465: return null;
0466: }
0467:
0468: /** Add a new local variable (in the current scope).
0469: * @param type type of the new Variable.
0470: * @return the new Variable. */
0471: public Variable addLocal(Type type) {
0472: return locals.current_scope.addVariable(this , type, null);
0473: }
0474:
0475: /** Add a new local variable (in the current scope).
0476: * @param type type of the new Variable.
0477: * @param name name of the new Variable.
0478: * @return the new Variable. */
0479: public Variable addLocal(Type type, String name) {
0480: return locals.current_scope.addVariable(this , type, name);
0481: }
0482:
0483: /** Call addLocal for parameters (as implied by method type). */
0484: public void addParamLocals() {
0485: Method method = getMethod();
0486: if ((method.access_flags & Access.STATIC) == 0)
0487: addLocal(method.classfile).setParameter(true);
0488: int arg_count = method.arg_types.length;
0489: for (int i = 0; i < arg_count; i++)
0490: addLocal(method.arg_types[i]).setParameter(true);
0491: }
0492:
0493: public final void emitPushConstant(int val, Type type) {
0494: switch (type.getSignature().charAt(0)) {
0495: case 'B':
0496: case 'C':
0497: case 'I':
0498: case 'Z':
0499: case 'S':
0500: emitPushInt(val);
0501: break;
0502: case 'J':
0503: emitPushLong((long) val);
0504: break;
0505: case 'F':
0506: emitPushFloat((float) val);
0507: break;
0508: case 'D':
0509: emitPushDouble((double) val);
0510: break;
0511: default:
0512: throw new Error("bad type to emitPushConstant");
0513: }
0514: }
0515:
0516: public final void emitPushConstant(CpoolEntry cnst) {
0517: reserve(3);
0518: int index = cnst.index;
0519: if (cnst instanceof CpoolValue2) {
0520: put1(20); // ldc2w
0521: put2(index);
0522: } else if (index < 256) {
0523: put1(18); // ldc1
0524: put1(index);
0525: } else {
0526: put1(19); // ldc2
0527: put2(index);
0528: }
0529: }
0530:
0531: public final void emitPushBoolean(boolean b) {
0532: reserve(1);
0533: put1(b ? 4 : 3);
0534: pushType(Type.boolean_type);
0535: }
0536:
0537: public final void emitPushInt(int i) {
0538: reserve(3);
0539: if (i >= -1 && i <= 5)
0540: put1(i + 3); // iconst_m1 .. iconst_5
0541: else if (i >= -128 && i < 128) {
0542: put1(16); // bipush
0543: put1(i);
0544: } else if (i >= -32768 && i < 32768) {
0545: put1(17); // sipush
0546: put2(i);
0547: } else {
0548: emitPushConstant(getConstants().addInt(i));
0549: }
0550: pushType(Type.int_type);
0551: }
0552:
0553: public void emitPushLong(long i) {
0554: if (i == 0 || i == 1) {
0555: reserve(1);
0556: put1(9 + (int) i); // lconst_0 .. lconst_1
0557: } else if ((long) (int) i == i) {
0558: emitPushInt((int) i);
0559: reserve(1);
0560: popType();
0561: put1(133); // i2l
0562: } else {
0563: emitPushConstant(getConstants().addLong(i));
0564: }
0565: pushType(Type.long_type);
0566: }
0567:
0568: public void emitPushFloat(float x) {
0569: int xi = (int) x;
0570: if ((float) xi == x && xi >= -128 && xi < 128) {
0571: if (xi >= 0 && xi <= 2) {
0572: reserve(1);
0573: put1(11 + xi); // fconst_0 .. fconst_2
0574: if (xi == 0 && Float.floatToIntBits(x) != 0) // x == -0.0
0575: {
0576: reserve(1);
0577: put1(118); // fneg
0578: }
0579: } else {
0580: // Saves space in the constant pool
0581: // Probably faster, at least on modern CPUs.
0582: emitPushInt(xi);
0583: reserve(1);
0584: popType();
0585: put1(134); // i2f
0586: }
0587: } else {
0588: emitPushConstant(getConstants().addFloat(x));
0589: }
0590: pushType(Type.float_type);
0591: }
0592:
0593: public void emitPushDouble(double x) {
0594: int xi = (int) x;
0595: if ((double) xi == x && xi >= -128 && xi < 128) {
0596: if (xi == 0 || xi == 1) {
0597: reserve(1);
0598: put1(14 + xi); // dconst_0 or dconst_1
0599: if (xi == 0 && Double.doubleToLongBits(x) != 0L) // x == -0.0
0600: {
0601: reserve(1);
0602: put1(119); // dneg
0603: }
0604: } else {
0605: // Saves space in the constant pool
0606: // Probably faster, at least on modern CPUs.
0607: emitPushInt(xi);
0608: reserve(1);
0609: popType();
0610: put1(135); // i2d
0611: }
0612: } else {
0613: emitPushConstant(getConstants().addDouble(x));
0614: }
0615: pushType(Type.double_type);
0616: }
0617:
0618: public final void emitPushString(String str) {
0619: emitPushConstant(getConstants().addString(str));
0620: pushType(Type.string_type);
0621: }
0622:
0623: public void emitPushNull() {
0624: emitPushNull(Type.pointer_type);
0625: }
0626:
0627: /**
0628: @param type the type <code>null</code> is considered to have.
0629: */
0630: public void emitPushNull(Type type) {
0631: reserve(1);
0632: put1(1); // aconst_null
0633: pushType(type);
0634: }
0635:
0636: public final void emitPushThis() {
0637: reserve(1);
0638: put1(42); // aload_0
0639: pushType(getMethod().getDeclaringClass());
0640: }
0641:
0642: void emitNewArray(int type_code) {
0643: reserve(2);
0644: put1(188); // newarray
0645: put1(type_code);
0646: }
0647:
0648: public final void emitArrayLength() {
0649: if (!(popType() instanceof ArrayType))
0650: throw new Error("non-array type in emitArrayLength");
0651:
0652: reserve(1);
0653: put1(190); // arraylength
0654: pushType(Type.int_type);
0655: }
0656:
0657: /* Returns an integer in the range 0 (for 'int') through 4 (for object
0658: reference) to 7 (for 'short') which matches the pattern of how JVM
0659: opcodes typically depend on the operand type. */
0660:
0661: private int adjustTypedOp(char sig) {
0662: switch (sig) {
0663: case 'I':
0664: return 0; // int
0665: case 'J':
0666: return 1; // long
0667: case 'F':
0668: return 2; // float
0669: case 'D':
0670: return 3; // double
0671: default:
0672: return 4; // object
0673: case 'B':
0674: case 'Z':
0675: return 5; // byte or boolean
0676: case 'C':
0677: return 6; // char
0678: case 'S':
0679: return 7; // short
0680: }
0681: }
0682:
0683: private int adjustTypedOp(Type type) {
0684: return adjustTypedOp(type.getSignature().charAt(0));
0685: }
0686:
0687: private void emitTypedOp(int op, Type type) {
0688: reserve(1);
0689: put1(op + adjustTypedOp(type));
0690: }
0691:
0692: private void emitTypedOp(int op, char sig) {
0693: reserve(1);
0694: put1(op + adjustTypedOp(sig));
0695: }
0696:
0697: /** Store into an element of an array.
0698: * Must already have pushed the array reference, the index,
0699: * and the new value (in that order).
0700: * Stack: ..., array, index, value => ...
0701: */
0702: public void emitArrayStore(Type element_type) {
0703: popType(); // Pop new value
0704: popType(); // Pop index
0705: popType(); // Pop array reference
0706: emitTypedOp(79, element_type);
0707: }
0708:
0709: /** Load an element from an array.
0710: * Must already have pushed the array and the index (in that order):
0711: * Stack: ..., array, index => ..., value */
0712: public void emitArrayLoad(Type element_type) {
0713: popType(); // Pop index
0714: popType(); // Pop array reference
0715: emitTypedOp(46, element_type);
0716: pushType(element_type);
0717: }
0718:
0719: /** Load an element from an array.
0720: * Must already have pushed the array and the index (in that order):
0721: * Stack: ..., array, index => ..., value */
0722: public void emitArrayLoad() {
0723: popType(); // Pop index
0724: ArrayType arrayType = (ArrayType) popType(); // Pop array reference
0725: Type elementType = arrayType.getComponentType();
0726: emitTypedOp(46, elementType);
0727: pushType(elementType);
0728: }
0729:
0730: /**
0731: * Invoke new on a class type.
0732: * Does not call the constructor!
0733: * @param type the desired new object type
0734: */
0735: public void emitNew(ClassType type) {
0736: reserve(3);
0737: put1(187); // new
0738: putIndex2(getConstants().addClass(type));
0739: pushType(type);
0740: }
0741:
0742: /** Compile code to allocate a new array.
0743: * The size should have been already pushed on the stack.
0744: * @param type type of the array elements
0745: */
0746: public void emitNewArray(Type element_type, int dims) {
0747: Type top = popType().promote();
0748: if (top != Type.int_type)
0749: throw new Error("non-int dim. spec. in emitNewArray");
0750:
0751: if (element_type instanceof PrimType) {
0752: int code;
0753: switch (element_type.getSignature().charAt(0)) {
0754: case 'B':
0755: code = 8;
0756: break;
0757: case 'S':
0758: code = 9;
0759: break;
0760: case 'I':
0761: code = 10;
0762: break;
0763: case 'J':
0764: code = 11;
0765: break;
0766: case 'F':
0767: code = 6;
0768: break;
0769: case 'D':
0770: code = 7;
0771: break;
0772: case 'Z':
0773: code = 4;
0774: break;
0775: case 'C':
0776: code = 5;
0777: break;
0778: default:
0779: throw new Error("bad PrimType in emitNewArray");
0780: }
0781: emitNewArray(code);
0782: } else if (element_type instanceof ArrayType) {
0783: reserve(4);
0784: put1(197); // multianewarray
0785: putIndex2(getConstants().addClass(
0786: new ArrayType(element_type)));
0787: if (dims < 1 || dims > 255)
0788: throw new Error("dims out of range in emitNewArray");
0789: put1(dims);
0790: while (--dims > 0) // first dim already popped
0791: {
0792: top = popType().promote();
0793: if (top != Type.int_type)
0794: throw new Error(
0795: "non-int dim. spec. in emitNewArray");
0796: }
0797: } else if (element_type instanceof ObjectType) {
0798: reserve(3);
0799: put1(189); // anewarray
0800: putIndex2(getConstants()
0801: .addClass((ObjectType) element_type));
0802: } else
0803: throw new Error("unimplemented type in emitNewArray");
0804:
0805: pushType(new ArrayType(element_type));
0806: }
0807:
0808: public void emitNewArray(Type element_type) {
0809: emitNewArray(element_type, 1);
0810: }
0811:
0812: // We may want to deprecate this, because it depends on popType.
0813: private void emitBinop(int base_code) {
0814: Type type2 = popType().promote();
0815: Type type1_raw = popType();
0816: Type type1 = type1_raw.promote();
0817: if (type1 != type2 || !(type1 instanceof PrimType))
0818: throw new Error(
0819: "non-matching or bad types in binary operation");
0820: emitTypedOp(base_code, type1);
0821: pushType(type1_raw);
0822: }
0823:
0824: private void emitBinop(int base_code, char sig) {
0825: popType();
0826: popType();
0827: emitTypedOp(base_code, sig);
0828: pushType(Type.signatureToPrimitive(sig));
0829: }
0830:
0831: private void emitBinop(int base_code, Type type) {
0832: popType();
0833: popType();
0834: emitTypedOp(base_code, type);
0835: pushType(type);
0836: }
0837:
0838: // public final void emitIntAdd () { put1(96); popType();}
0839: // public final void emitLongAdd () { put1(97); popType();}
0840: // public final void emitFloatAdd () { put1(98); popType();}
0841: // public final void emitDoubleAdd () { put1(99); popType();}
0842:
0843: public final void emitAdd(char sig) {
0844: emitBinop(96, sig);
0845: }
0846:
0847: public final void emitAdd(PrimType type) {
0848: emitBinop(96, type);
0849: }
0850:
0851: /** @deprecated */
0852: public final void emitAdd() {
0853: emitBinop(96);
0854: }
0855:
0856: public final void emitSub(char sig) {
0857: emitBinop(100, sig);
0858: }
0859:
0860: public final void emitSub(PrimType type) {
0861: emitBinop(100, type);
0862: }
0863:
0864: /** @deprecated */
0865: public final void emitSub() {
0866: emitBinop(100);
0867: }
0868:
0869: public final void emitMul() {
0870: emitBinop(104);
0871: }
0872:
0873: public final void emitDiv() {
0874: emitBinop(108);
0875: }
0876:
0877: public final void emitRem() {
0878: emitBinop(112);
0879: }
0880:
0881: public final void emitAnd() {
0882: emitBinop(126);
0883: }
0884:
0885: public final void emitIOr() {
0886: emitBinop(128);
0887: }
0888:
0889: public final void emitXOr() {
0890: emitBinop(130);
0891: }
0892:
0893: public final void emitShl() {
0894: emitShift(120);
0895: }
0896:
0897: public final void emitShr() {
0898: emitShift(122);
0899: }
0900:
0901: public final void emitUshr() {
0902: emitShift(124);
0903: }
0904:
0905: private void emitShift(int base_code) {
0906: Type type2 = popType().promote();
0907: Type type1_raw = popType();
0908: Type type1 = type1_raw.promote();
0909:
0910: if (type2 != Type.int_type)
0911: throw new Error("the amount of shift must be an int");
0912: if (type1 != Type.int_type && type1 != Type.long_type)
0913: throw new Error(
0914: "the value shifted must be an int or a long");
0915: emitTypedOp(base_code, type1);
0916: pushType(type1_raw);
0917: }
0918:
0919: /** Unary numerical negation (-). */
0920: public final void emitNeg() {
0921: Type type = popType().promote();
0922: emitTypedOp(116, type);
0923: pushType(type);
0924: }
0925:
0926: public final void emitNot(Type type) {
0927: emitPushConstant(1, type);
0928: emitAdd();
0929: emitPushConstant(1, type);
0930: emitAnd();
0931: }
0932:
0933: public void emitPrimop(int opcode, int arg_count, Type retType) {
0934: reserve(1);
0935: while (--arg_count >= 0)
0936: popType();
0937: put1(opcode);
0938: pushType(retType);
0939: }
0940:
0941: void emitMaybeWide(int opcode, int index) {
0942: if (index >= 256) {
0943: put1(196); // wide
0944: put1(opcode);
0945: put2(index);
0946: } else {
0947: put1(opcode);
0948: put1(index);
0949: }
0950: }
0951:
0952: /**
0953: * Comple code to push the contents of a local variable onto the statck.
0954: * @param var The variable whose contents we want to push.
0955: */
0956: public final void emitLoad(Variable var) {
0957: if (var.dead())
0958: throw new Error("attempting to push dead variable");
0959: int offset = var.offset;
0960: if (offset < 0 || !var.isSimple())
0961: throw new Error(
0962: "attempting to load from unassigned variable "
0963: + var + " simple:" + var.isSimple()
0964: + ", offset: " + offset);
0965: Type type = var.getType().promote();
0966: reserve(4);
0967: int kind = adjustTypedOp(type);
0968: if (offset <= 3)
0969: put1(26 + 4 * kind + offset); // [ilfda]load_[0123]
0970: else
0971: emitMaybeWide(21 + kind, offset); // [ilfda]load
0972: pushType(var.getType());
0973: }
0974:
0975: public void emitStore(Variable var) {
0976: if (var.dead())
0977: throw new Error("attempting to push dead variable" + var);
0978: int offset = var.offset;
0979: if (offset < 0 || !var.isSimple())
0980: throw new Error(
0981: "attempting to store in unassigned variable "
0982: + var.getName() + " simple:"
0983: + var.isSimple() + ", offset: " + offset);
0984: Type type = var.getType().promote();
0985: reserve(4);
0986: popType();
0987: int kind = adjustTypedOp(type);
0988: if (offset <= 3)
0989: put1(59 + 4 * kind + offset); // [ilfda]store_[0123]
0990: else
0991: emitMaybeWide(54 + kind, offset); // [ilfda]store
0992: }
0993:
0994: public void emitInc(Variable var, short inc) {
0995: if (var.dead())
0996: throw new Error("attempting to increment dead variable");
0997: int offset = var.offset;
0998: if (offset < 0 || !var.isSimple())
0999: throw new Error(
1000: "attempting to increment unassigned variable"
1001: + var.getName() + " simple:"
1002: + var.isSimple() + ", offset: " + offset);
1003: Type type = var.getType().promote();
1004: reserve(6);
1005: if (type != Type.int_type)
1006: throw new Error("attempting to increment non-int variable");
1007:
1008: boolean wide = offset > 255 || inc > 255 || inc < -256;
1009:
1010: if (wide) {
1011: put1(196); // wide
1012: put1(132); // iinc
1013: put2(offset);
1014: put2(inc);
1015: } else {
1016: put1(132); // iinc
1017: put1(offset);
1018: put1(inc);
1019: }
1020: }
1021:
1022: private final void emitFieldop(Field field, int opcode) {
1023: reserve(3);
1024: put1(opcode);
1025: putIndex2(getConstants().addFieldRef(field));
1026: }
1027:
1028: /** Compile code to get a static field value.
1029: * Stack: ... => ..., value */
1030:
1031: public final void emitGetStatic(Field field) {
1032: pushType(field.type);
1033: emitFieldop(field, 178); // getstatic
1034: }
1035:
1036: /** Compile code to get a non-static field value.
1037: * Stack: ..., objectref => ..., value */
1038:
1039: public final void emitGetField(Field field) {
1040: popType();
1041: pushType(field.type);
1042: emitFieldop(field, 180); // getfield
1043: }
1044:
1045: /** Compile code to put a static field value.
1046: * Stack: ..., value => ... */
1047:
1048: public final void emitPutStatic(Field field) {
1049: popType();
1050: emitFieldop(field, 179); // putstatic
1051: }
1052:
1053: /** Compile code to put a non-static field value.
1054: * Stack: ..., objectref, value => ... */
1055:
1056: public final void emitPutField(Field field) {
1057: popType();
1058: popType();
1059: emitFieldop(field, 181); // putfield
1060: }
1061:
1062: /** Comptes the number of stack words taken by a list of types. */
1063: private int words(Type[] types) {
1064: int res = 0;
1065: for (int i = types.length; --i >= 0;)
1066: if (types[i].size > 4)
1067: res += 2;
1068: else
1069: res++;
1070: return res;
1071: }
1072:
1073: public void emitInvokeMethod(Method method, int opcode) {
1074: reserve(opcode == 185 ? 5 : 3);
1075: int arg_count = method.arg_types.length;
1076: boolean is_invokestatic = opcode == 184;
1077: if (is_invokestatic != ((method.access_flags & Access.STATIC) != 0))
1078: throw new Error(
1079: "emitInvokeXxx static flag mis-match method.flags="
1080: + method.access_flags);
1081: Type receiverType = null;
1082:
1083: while (--arg_count >= 0)
1084: popType();
1085: if (!is_invokestatic) {
1086: arg_count++;
1087: receiverType = popType();
1088: // Don't change anything if the call is an invokespecial
1089: if (opcode != 183
1090: && receiverType != method.getDeclaringClass()) {
1091: // We try to find a more precise method, given the known
1092: // type of the receiver.
1093: Method preciseMethod = receiverType
1094: .refineMethod(method);
1095:
1096: if (preciseMethod != null &&
1097: // Don't choose a more precise method if it is an
1098: // interface method, and the original is a class method
1099: // (can happen if the original class is Object, like in
1100: // Object.equals, refined in List.equals).
1101: ((!preciseMethod.getDeclaringClass()
1102: .isInterface()) || method
1103: .getDeclaringClass().isInterface())) {
1104: method = preciseMethod;
1105: // It could be that the call was an invokeinterface, and
1106: // now became an invokevirtual.
1107: if (opcode == 185
1108: && !method.getDeclaringClass()
1109: .isInterface())
1110: opcode = 182;
1111: }
1112: }
1113: }
1114:
1115: if (!Access.legal(getMethod().getDeclaringClass(), method,
1116: receiverType))
1117: throw new VerificationError("Method " + method.toString()
1118: + " is not accessible");
1119:
1120: put1(opcode); // invokevirtual, invokespecial, or invokestatic
1121: putIndex2(getConstants().addMethodRef(method));
1122: if (opcode == 185) // invokeinterface
1123: {
1124: put1(words(method.arg_types) + 1); // 1 word for 'this'
1125: put1(0);
1126: }
1127: if (method.return_type.size != 0)
1128: pushType(method.return_type);
1129: }
1130:
1131: public void emitInvoke(Method method) {
1132: int opcode;
1133: if ((method.access_flags & Access.STATIC) != 0)
1134: opcode = 184; // invokestatic
1135: else if (method.classfile.isInterface())
1136: opcode = 185; // invokeinterface
1137: else
1138: opcode = 182; // invokevirtual
1139: emitInvokeMethod(method, opcode);
1140: }
1141:
1142: /** Compile a virtual method call.
1143: * The stack contains the 'this' object, followed by the arguments in order.
1144: * @param method the method to invoke virtually
1145: */
1146: public void emitInvokeVirtual(Method method) {
1147: emitInvokeMethod(method, 182); // invokevirtual
1148: }
1149:
1150: public void emitInvokeSpecial(Method method) {
1151: emitInvokeMethod(method, 183); // invokespecial
1152: }
1153:
1154: /** Compile a static method call.
1155: * The stack contains the the arguments in order.
1156: * @param method the static method to invoke
1157: */
1158: public void emitInvokeStatic(Method method) {
1159: emitInvokeMethod(method, 184); // invokestatic
1160: }
1161:
1162: public void emitInvokeInterface(Method method) {
1163: emitInvokeMethod(method, 185); // invokeinterface
1164: }
1165:
1166: final void emitTransfer(Label label, int opcode) {
1167: put1(opcode);
1168: label.emit(this );
1169: }
1170:
1171: /** Compile an unconditional branch (goto) or a jsr.
1172: * @param label target of the branch (must be in this method).
1173: */
1174: public final void emitGoto(Label label, int opcode) {
1175: reserve(5);
1176: if (label.defined()) {
1177: readPC = PC;
1178: int delta = label.position - PC;
1179: if (delta < -32768) {
1180: put1(opcode - 167); // goto_w or jsr_w
1181: put4(delta);
1182: } else {
1183: put1(opcode); // goto or jsr
1184: put2(delta);
1185: }
1186: } else
1187: emitTransfer(label, opcode); // goto label or jsr label
1188: }
1189:
1190: /** Compile an unconditional branch (goto).
1191: * @param label target of the branch (must be in this method).
1192: */
1193: public final void emitGoto(Label label) {
1194: emitGoto(label, 167);
1195: setUnreachable();
1196: }
1197:
1198: public final void emitJsr(Label label) {
1199: emitGoto(label, 168);
1200: }
1201:
1202: public final void emitGotoIfEq(Label label, boolean invert) {
1203: Type type2 = popType().promote();
1204: Type type1 = popType().promote();
1205: reserve(4);
1206: int opcode;
1207: char sig1 = type1.getSignature().charAt(0);
1208: char sig2 = type2.getSignature().charAt(0);
1209: if (sig1 == 'I' && sig2 == 'I')
1210: opcode = 159; // if_icmpeq (inverted: if_icmpne)
1211: else if (sig1 == 'J' && sig2 == 'J') {
1212: put1(148); // lcmp
1213: opcode = 153; // ifeq (inverted: ifne)
1214: } else if (sig1 == 'F' && sig2 == 'F') {
1215: put1(149); // fcmpl
1216: opcode = 153; // ifeq (inverted: ifne)
1217: } else if (sig1 == 'D' && sig2 == 'D') {
1218: put1(151); // dcmpl
1219: opcode = 153; // ifeq (inverted: ifne)
1220: } else if ((sig1 == 'L' || sig1 == '[')
1221: && (sig2 == 'L' || sig2 == '['))
1222: opcode = 165; // if_acmpeq (inverted: if_acmpne)
1223: else
1224: throw new Error("non-matching types to emitGotoIfEq");
1225: if (invert)
1226: opcode++;
1227: emitTransfer(label, opcode);
1228: }
1229:
1230: /** Compile a conditional transfer if 2 top stack elements are equal. */
1231: public final void emitGotoIfEq(Label label) {
1232: emitGotoIfEq(label, false);
1233: }
1234:
1235: /** Compile conditional transfer if 2 top stack elements are not equal. */
1236: public final void emitGotoIfNE(Label label) {
1237: emitGotoIfEq(label, true);
1238: }
1239:
1240: public final void emitGotoIfCompare1(Label label, int opcode) {
1241: popType();
1242: reserve(3);
1243: emitTransfer(label, opcode);
1244: }
1245:
1246: public final void emitGotoIfIntEqZero(Label label) {
1247: emitGotoIfCompare1(label, 153);
1248: }
1249:
1250: public final void emitGotoIfIntNeZero(Label label) {
1251: emitGotoIfCompare1(label, 154);
1252: }
1253:
1254: public final void emitGotoIfIntLtZero(Label label) {
1255: emitGotoIfCompare1(label, 155);
1256: }
1257:
1258: public final void emitGotoIfIntGeZero(Label label) {
1259: emitGotoIfCompare1(label, 156);
1260: }
1261:
1262: public final void emitGotoIfIntGtZero(Label label) {
1263: emitGotoIfCompare1(label, 157);
1264: }
1265:
1266: public final void emitGotoIfIntLeZero(Label label) {
1267: emitGotoIfCompare1(label, 158);
1268: }
1269:
1270: public final void emitGotoIfNull(Label label) {
1271: emitGotoIfCompare1(label, 198);
1272: } //ifnull
1273:
1274: public final void emitGotoIfNotNull(Label label) {
1275: emitGotoIfCompare1(label, 199);
1276: } //ifnonnull
1277:
1278: public final void emitGotoIfCompare2(Label label, int logop) {
1279: if (logop < 155 || logop > 158)
1280: throw new Error(
1281: "emitGotoIfCompare2: logop must be one of iflt, ifgt, ifle, ifge");
1282:
1283: Type type2 = popType().promote();
1284: Type type1 = popType().promote();
1285: reserve(4);
1286: char sig1 = type1.getSignature().charAt(0);
1287: char sig2 = type2.getSignature().charAt(0);
1288:
1289: boolean cmpg = (logop == 155 || logop == 158); // iflt,ifle
1290:
1291: if (sig1 == 'I' && sig2 == 'I')
1292: logop += 6; // iflt -> if_icmplt etc.
1293: else if (sig1 == 'J' && sig2 == 'J')
1294: put1(148); // lcmp
1295: else if (sig1 == 'F' && sig2 == 'F')
1296: put1(cmpg ? 149 : 150); // fcmpl/fcmpg
1297: else if (sig1 == 'D' && sig2 == 'D')
1298: put1(cmpg ? 151 : 152); // dcmpl/dcmpg
1299: else
1300: throw new Error("non-matching types to emitGotoIfCompare2");
1301:
1302: emitTransfer(label, logop);
1303: }
1304:
1305: // binary comparisons
1306: public final void emitGotoIfLt(Label label) {
1307: emitGotoIfCompare2(label, 155);
1308: }
1309:
1310: public final void emitGotoIfGe(Label label) {
1311: emitGotoIfCompare2(label, 156);
1312: }
1313:
1314: public final void emitGotoIfGt(Label label) {
1315: emitGotoIfCompare2(label, 157);
1316: }
1317:
1318: public final void emitGotoIfLe(Label label) {
1319: emitGotoIfCompare2(label, 158);
1320: }
1321:
1322: /** Compile start of a conditional: if (!(x OPCODE 0)) ...
1323: * The value of x must already have been pushed. */
1324: public final void emitIfCompare1(int opcode) {
1325: IfState new_if = new IfState(this );
1326: if (popType().promote() != Type.int_type)
1327: throw new Error("non-int type to emitIfCompare1");
1328: reserve(3);
1329: emitTransfer(new_if.end_label, opcode);
1330: new_if.start_stack_size = SP;
1331: }
1332:
1333: /** Compile start of conditional: if (x != 0) ...
1334: * Also use this if you have pushed a boolean value: if (b) ... */
1335: public final void emitIfIntNotZero() {
1336: emitIfCompare1(153); // ifeq
1337: }
1338:
1339: /** Compile start of conditional: if (x == 0) ...
1340: * Also use this if you have pushed a boolean value: if (!b) ... */
1341: public final void emitIfIntZero() {
1342: emitIfCompare1(154); // ifne
1343: }
1344:
1345: /** Compile start of conditional: if (x <= 0) */
1346: public final void emitIfIntLEqZero() {
1347: emitIfCompare1(157); // ifgt
1348: }
1349:
1350: /** Compile start of a conditional: if (!(x OPCODE null)) ...
1351: * The value of x must already have been pushed and must be of
1352: * reference type. */
1353: public final void emitIfRefCompare1(int opcode) {
1354: IfState new_if = new IfState(this );
1355: if (!(popType() instanceof ObjectType))
1356: throw new Error("non-ref type to emitIfRefCompare1");
1357: reserve(3);
1358: emitTransfer(new_if.end_label, opcode);
1359: new_if.start_stack_size = SP;
1360: }
1361:
1362: /** Compile start of conditional: if (x != null) */
1363: public final void emitIfNotNull() {
1364: emitIfRefCompare1(198); // ifnull
1365: }
1366:
1367: /** Compile start of conditional: if (x == null) */
1368: public final void emitIfNull() {
1369: emitIfRefCompare1(199); // ifnonnull
1370: }
1371:
1372: /** Compile start of a conditional: if (!(x OPCODE y)) ...
1373: * The value of x and y must already have been pushed. */
1374: public final void emitIfIntCompare(int opcode) {
1375: IfState new_if = new IfState(this );
1376: popType();
1377: popType();
1378: reserve(3);
1379: emitTransfer(new_if.end_label, opcode);
1380: new_if.start_stack_size = SP;
1381: }
1382:
1383: /* Compile start of a conditional: if (x < y) ... */
1384: public final void emitIfIntLt() {
1385: emitIfIntCompare(162); // if_icmpge
1386: }
1387:
1388: /** Compile start of a conditional: if (x != y) ...
1389: * The values of x and y must already have been pushed. */
1390: public final void emitIfNEq() {
1391: IfState new_if = new IfState(this );
1392: emitGotoIfEq(new_if.end_label);
1393: new_if.start_stack_size = SP;
1394: }
1395:
1396: /** Compile start of a conditional: if (x == y) ...
1397: * The values of x and y must already have been pushed. */
1398: public final void emitIfEq() {
1399: IfState new_if = new IfState(this );
1400: emitGotoIfNE(new_if.end_label);
1401: new_if.start_stack_size = SP;
1402: }
1403:
1404: /** Compile start of a conditional: if (x < y) ...
1405: * The values of x and y must already have been pushed. */
1406: public final void emitIfLt() {
1407: IfState new_if = new IfState(this );
1408: emitGotoIfGe(new_if.end_label);
1409: new_if.start_stack_size = SP;
1410: }
1411:
1412: /** Compile start of a conditional: if (x >= y) ...
1413: * The values of x and y must already have been pushed. */
1414: public final void emitIfGe() {
1415: IfState new_if = new IfState(this );
1416: emitGotoIfLt(new_if.end_label);
1417: new_if.start_stack_size = SP;
1418: }
1419:
1420: /** Compile start of a conditional: if (x > y) ...
1421: * The values of x and y must already have been pushed. */
1422: public final void emitIfGt() {
1423: IfState new_if = new IfState(this );
1424: emitGotoIfLe(new_if.end_label);
1425: new_if.start_stack_size = SP;
1426: }
1427:
1428: /** Compile start of a conditional: if (x <= y) ...
1429: * The values of x and y must already have been pushed. */
1430: public final void emitIfLe() {
1431: IfState new_if = new IfState(this );
1432: emitGotoIfGt(new_if.end_label);
1433: new_if.start_stack_size = SP;
1434: }
1435:
1436: /** Emit a 'ret' instruction.
1437: * @param var the variable containing the return address */
1438: public void emitRet(Variable var) {
1439: int offset = var.offset;
1440: if (offset < 256) {
1441: reserve(2);
1442: put1(169); // ret
1443: put1(offset);
1444: } else {
1445: reserve(4);
1446: put1(196); // wide
1447: put1(169); // ret
1448: put2(offset);
1449: }
1450: }
1451:
1452: public final void emitIfThen() {
1453: new IfState(this , null);
1454: }
1455:
1456: /** Compile start of else clause. */
1457: public final void emitElse() {
1458: Label else_label = if_stack.end_label;
1459: Label end_label = new Label(this );
1460: if_stack.end_label = end_label;
1461: if (reachableHere()) {
1462: int growth = SP - if_stack.start_stack_size;
1463: if_stack.stack_growth = growth;
1464: if (growth > 0) {
1465: if_stack.then_stacked_types = new Type[growth];
1466: System.arraycopy(stack_types,
1467: if_stack.start_stack_size,
1468: if_stack.then_stacked_types, 0, growth);
1469: } else
1470: if_stack.then_stacked_types = new Type[0]; // ???
1471: emitGoto(end_label);
1472: }
1473: while (SP > if_stack.start_stack_size)
1474: popType();
1475: SP = if_stack.start_stack_size;
1476: if (else_label != null)
1477: else_label.define(this );
1478: if_stack.doing_else = true;
1479: }
1480:
1481: /** Compile end of conditional. */
1482: public final void emitFi() {
1483: boolean make_unreachable = false;
1484: if (!if_stack.doing_else) { // There was no 'else' clause.
1485: if (reachableHere() && SP != if_stack.start_stack_size)
1486: throw new Error(
1487: "at PC "
1488: + PC
1489: + " then clause grows stack with no else clause");
1490: } else if (if_stack.then_stacked_types != null) {
1491: int then_clause_stack_size = if_stack.start_stack_size
1492: + if_stack.stack_growth;
1493: if (!reachableHere()) {
1494: if (if_stack.stack_growth > 0)
1495: System.arraycopy(if_stack.then_stacked_types, 0,
1496: stack_types, if_stack.start_stack_size,
1497: if_stack.stack_growth);
1498: SP = then_clause_stack_size;
1499: } else if (SP != then_clause_stack_size) {
1500: for (int i = 0; i < if_stack.then_stacked_types.length; i++)
1501: System.out.println("Stack[" + i + "] = "
1502: + if_stack.then_stacked_types[i]);
1503: throw new Error("at PC " + PC
1504: + ": SP at end of 'then' was "
1505: + then_clause_stack_size
1506: + " while SP at end of 'else' was " + SP);
1507: } else {
1508: // Reconcile the types on the stack.
1509: for (int i = 0; i < if_stack.then_stacked_types.length; i++) {
1510: Type t1 = if_stack.then_stacked_types[i];
1511: Type t2 = stack_types[if_stack.start_stack_size + i];
1512:
1513: Type common = Type.lowestCommonSuperType(t1, t2);
1514: if (common == null)
1515: common = Type.pointer_type;
1516:
1517: stack_types[if_stack.start_stack_size + i] = common;
1518: }
1519: }
1520: } else if (unreachable_here)
1521: make_unreachable = true;
1522:
1523: if (if_stack.end_label != null)
1524: if_stack.end_label.define(this );
1525: if (make_unreachable)
1526: setUnreachable();
1527: // Pop the if_stack.
1528: if_stack = if_stack.previous;
1529: }
1530:
1531: public final void emitConvert(Type from, Type to) {
1532: String to_sig = to.getSignature();
1533: String from_sig = from.getSignature();
1534: int op = -1;
1535: if (to_sig.length() == 1 || from_sig.length() == 1) {
1536: char to_sig0 = to_sig.charAt(0);
1537: char from_sig0 = from_sig.charAt(0);
1538: if (from_sig0 == to_sig0)
1539: return;
1540: if (from.size < 4)
1541: from_sig0 = 'I';
1542: if (to.size < 4) {
1543: emitConvert(from, Type.int_type);
1544: from_sig0 = 'I';
1545: }
1546: if (from_sig0 == to_sig0)
1547: return;
1548: switch (from_sig0) {
1549: case 'I':
1550: switch (to_sig0) {
1551: case 'B':
1552: op = 145;
1553: break; // i2b
1554: case 'C':
1555: op = 146;
1556: break; // i2c
1557: case 'S':
1558: op = 147;
1559: break; // i2s
1560: case 'J':
1561: op = 133;
1562: break; // i2l
1563: case 'F':
1564: op = 134;
1565: break; // i2f
1566: case 'D':
1567: op = 135;
1568: break; // i2d
1569: }
1570: break;
1571: case 'J':
1572: switch (to_sig0) {
1573: case 'I':
1574: op = 136;
1575: break; // l2i
1576: case 'F':
1577: op = 137;
1578: break; // l2f
1579: case 'D':
1580: op = 138;
1581: break; // l2d
1582: }
1583: break;
1584: case 'F':
1585: switch (to_sig0) {
1586: case 'I':
1587: op = 139;
1588: break; // f2i
1589: case 'J':
1590: op = 140;
1591: break; // f2l
1592: case 'D':
1593: op = 141;
1594: break; // f2d
1595: }
1596: break;
1597: case 'D':
1598: switch (to_sig0) {
1599: case 'I':
1600: op = 142;
1601: break; // d2i
1602: case 'J':
1603: op = 143;
1604: break; // d2l
1605: case 'F':
1606: op = 144;
1607: break; // d2f
1608: }
1609: break;
1610: }
1611: }
1612: if (op < 0)
1613: throw new Error("unsupported CodeAttr.emitConvert from "
1614: + from + " to " + to);
1615: reserve(1);
1616: popType();
1617: put1(op);
1618: pushType(to);
1619: }
1620:
1621: private void emitCheckcast(Type type, int opcode) {
1622: reserve(3);
1623: popType();
1624: put1(opcode);
1625: // if (type instanceof ArrayType)
1626: // {
1627: // ArrayType atype = (ArrayType) type;
1628: // CpoolUtf8 name = getConstants().addUtf8(atype.signature);
1629: // putIndex2(getConstants().addClass(name));
1630: // } else
1631: if (type instanceof ObjectType) {
1632: putIndex2(getConstants().addClass((ObjectType) type));
1633: } else
1634: throw new Error("unimplemented type " + type
1635: + " in emitCheckcast/emitInstanceof");
1636: }
1637:
1638: public void emitCheckcast(Type type) {
1639: emitCheckcast(type, 192);
1640: pushType(type);
1641: }
1642:
1643: public void emitInstanceof(Type type) {
1644: emitCheckcast(type, 193);
1645: pushType(Type.boolean_type);
1646: }
1647:
1648: public final void emitThrow() {
1649: popType();
1650: reserve(1);
1651: put1(191); // athrow
1652: setUnreachable();
1653: }
1654:
1655: public final void emitMonitorEnter() {
1656: popType();
1657: reserve(1);
1658: put1(194); // monitorenter
1659: }
1660:
1661: public final void emitMonitorExit() {
1662: popType();
1663: reserve(1);
1664: put1(195); // monitorexit
1665: }
1666:
1667: private void callFinallyBlocks() {
1668: TryState state = try_stack;
1669:
1670: /* If a value is returned, it must be saved to a local variable,
1671: to prevent a verification error because of inconsistent stack sizes.
1672: */
1673: boolean saveResult = !getMethod().getReturnType().isVoid();
1674: Variable result = null;
1675:
1676: while (state != null) {
1677: if (state.finally_subr != null // there is a finally block
1678: && state.finally_ret_addr == null) // 'return' is not inside it
1679: {
1680: if (saveResult && result == null) {
1681: // We store the result in a method-level variable, to make sure
1682: // that the finally blocks do not use the same slot.
1683: result = methodScope().addVariable(this , topType(),
1684: null);
1685: emitStore(result);
1686: }
1687: emitJsr(state.finally_subr);
1688: }
1689:
1690: state = state.previous;
1691: }
1692:
1693: if (result != null)
1694: emitLoad(result);
1695: }
1696:
1697: /**
1698: * Compile a method return.
1699: */
1700: public final void emitReturn() {
1701: callFinallyBlocks();
1702: if (!checkPostcondition())
1703: emitRealReturn();
1704: }
1705:
1706: private void emitRealReturn() {
1707: if (getMethod().getReturnType().size == 0) {
1708: reserve(1);
1709: put1(177); // return
1710: } else
1711: emitTypedOp(172, popType().promote());
1712: setUnreachable();
1713: }
1714:
1715: /** Add an exception handler. */
1716: public void addHandler(int start_pc, int end_pc, int handler_pc,
1717: int catch_type) {
1718: int index = 4 * exception_table_length;
1719: if (exception_table == null) {
1720: exception_table = new short[20];
1721: } else if (exception_table.length <= index) {
1722: short[] new_table = new short[2 * exception_table.length];
1723: System.arraycopy(exception_table, 0, new_table, 0, index);
1724: exception_table = new_table;
1725: }
1726: exception_table[index++] = (short) start_pc;
1727: exception_table[index++] = (short) end_pc;
1728: exception_table[index++] = (short) handler_pc;
1729: exception_table[index++] = (short) catch_type;
1730: exception_table_length++;
1731: }
1732:
1733: /** Add an exception handler. */
1734: public void addHandler(int start_pc, int end_pc, int handler_pc,
1735: ClassType catch_type, ConstantPool constants) {
1736: int catch_type_index;
1737: if (catch_type == null)
1738: catch_type_index = 0;
1739: else
1740: catch_type_index = constants.addClass(catch_type).index;
1741: addHandler(start_pc, end_pc, handler_pc, catch_type_index);
1742: }
1743:
1744: public void emitTryStart(boolean has_finally, Type result_type) {
1745: Variable[] savedStack;
1746: if (SP > 0) {
1747: savedStack = new Variable[SP];
1748: int i = 0;
1749: while (SP > 0) {
1750: Variable var = addLocal(topType());
1751: emitStore(var);
1752: savedStack[i++] = var;
1753: }
1754: } else
1755: savedStack = null;
1756: TryState try_state = new TryState(this );
1757: try_state.savedStack = savedStack;
1758: if (result_type != null && result_type.size == 0) // void
1759: result_type = null;
1760: if (result_type != null || SP > 0) {
1761: pushScope();
1762: if (result_type != null)
1763: try_state.saved_result = addLocal(result_type);
1764: }
1765: if (has_finally)
1766: try_state.finally_subr = new Label(this );
1767: }
1768:
1769: public void emitTryEnd() {
1770: if (try_stack.end_label == null) {
1771: if (try_stack.saved_result != null)
1772: emitStore(try_stack.saved_result);
1773: try_stack.end_label = new Label(this );
1774: if (reachableHere()) {
1775: if (try_stack.finally_subr != null)
1776: emitGoto(try_stack.finally_subr, 168); // jsr
1777: emitGoto(try_stack.end_label);
1778: }
1779: readPC = PC;
1780: try_stack.end_pc = PC;
1781: }
1782: }
1783:
1784: public void emitCatchStart(Variable var) {
1785: emitTryEnd();
1786: SP = 0;
1787: if (try_stack.try_type != null)
1788: emitCatchEnd();
1789: ClassType type = var == null ? null : (ClassType) var.getType();
1790: try_stack.try_type = type;
1791: readPC = PC;
1792: addHandler(try_stack.start_pc, try_stack.end_pc, PC, type,
1793: getConstants());
1794: if (var != null) {
1795: pushType(type);
1796: emitStore(var);
1797: } else
1798: pushType(Type.throwable_type);
1799: }
1800:
1801: public void emitCatchStart(ClassType type) {
1802: emitTryEnd();
1803: SP = 0;
1804: if (try_stack.try_type != null)
1805: emitCatchEnd();
1806: try_stack.try_type = type;
1807: readPC = PC;
1808: addHandler(try_stack.start_pc, try_stack.end_pc, PC, type,
1809: getConstants());
1810: pushType(type);
1811: }
1812:
1813: public void emitCatchEnd() {
1814: if (reachableHere()) {
1815: if (try_stack.saved_result != null)
1816: emitStore(try_stack.saved_result);
1817: if (try_stack.finally_subr != null)
1818: emitGoto(try_stack.finally_subr, 168); // jsr
1819: emitGoto(try_stack.end_label);
1820: }
1821: try_stack.try_type = null;
1822: }
1823:
1824: public void emitFinallyStart() {
1825: emitTryEnd();
1826: if (try_stack.try_type != null)
1827: emitCatchEnd();
1828: readPC = PC;
1829: SP = 0;
1830: try_stack.end_pc = PC;
1831:
1832: pushScope();
1833: Type except_type = Type.pointer_type;
1834: Variable except = addLocal(except_type);
1835: emitCatchStart((Variable) null);
1836: emitStore(except);
1837: emitGoto(try_stack.finally_subr, 168); // jsr
1838: emitLoad(except);
1839: emitThrow();
1840:
1841: try_stack.finally_subr.define(this );
1842: Type ret_addr_type = Type.pointer_type;
1843: try_stack.finally_ret_addr = addLocal(ret_addr_type);
1844: pushType(ret_addr_type);
1845: emitStore(try_stack.finally_ret_addr);
1846: }
1847:
1848: public void emitFinallyEnd() {
1849: emitRet(try_stack.finally_ret_addr);
1850: setUnreachable();
1851: popScope();
1852: try_stack.finally_subr = null;
1853: }
1854:
1855: public void emitTryCatchEnd() {
1856: if (try_stack.finally_subr != null)
1857: emitFinallyEnd();
1858: try_stack.end_label.define(this );
1859: Variable[] vars = try_stack.savedStack;
1860: if (vars != null) {
1861: for (int i = vars.length; --i >= 0;) {
1862: Variable v = vars[i];
1863: if (v != null) {
1864: emitLoad(v);
1865: }
1866: }
1867: }
1868: if (try_stack.saved_result != null)
1869: emitLoad(try_stack.saved_result);
1870: if (try_stack.saved_result != null || vars != null)
1871: popScope();
1872: try_stack = try_stack.previous;
1873: }
1874:
1875: public final boolean isInTry() {
1876: // This also return true if we're in a catch clause, but that is
1877: // good enough for now.
1878: return try_stack != null;
1879: }
1880:
1881: /** Compile a tail-call to position 0 of the current procewure.
1882: * @param pop_args if true, copy argument registers (except this) from stack.
1883: * @param scope Scope whose start we jump back to. */
1884: public void emitTailCall(boolean pop_args, Scope scope) {
1885: if (pop_args) {
1886: Method meth = getMethod();
1887: int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0
1888: : 1;
1889: for (int i = meth.arg_types.length; --i >= 0;)
1890: arg_slots += meth.arg_types[i].size > 4 ? 2 : 1;
1891: for (int i = meth.arg_types.length; --i >= 0;) {
1892: arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1;
1893: emitStore(locals.used[arg_slots]);
1894: }
1895: }
1896: reserve(5);
1897: int start_pc = scope.start_pc;
1898: int delta = start_pc - PC;
1899: if (delta < -32768) {
1900: put1(200); // goto_w
1901: put4(delta);
1902: } else {
1903: put1(167); // goto
1904: put2(delta);
1905: }
1906: setUnreachable();
1907: }
1908:
1909: /* Make sure the label with oldest fixup is first in labels. */
1910: void reorder_fixups() {
1911: Label prev = null;
1912: Label cur;
1913: Label oldest = null;
1914: Label oldest_prev = null;
1915: int oldest_fixup = PC + 100;
1916: for (cur = labels; cur != null; cur = cur.next) {
1917: if (cur.fixups != null && cur.fixups[0] < oldest_fixup) {
1918: oldest = cur;
1919: oldest_prev = prev;
1920: oldest_fixup = cur.fixups[0];
1921: }
1922: prev = cur;
1923: }
1924: if (oldest != labels && oldest != null) {
1925: oldest_prev.next = oldest.next;
1926: oldest.next = labels;
1927: labels = oldest;
1928: }
1929: }
1930:
1931: public void finalize_labels() {
1932: while (labels != null && labels.fixups != null)
1933: labels.emit_spring(this );
1934: for (Label label = labels; label != null; label = label.next) {
1935: if (label.fixups != null || label.wide_fixups != null)
1936: throw new Error("undefined label");
1937: }
1938: }
1939:
1940: public void assignConstants(ClassType cl) {
1941: super .assignConstants(cl);
1942: for (;;) {
1943: CodeFragment frag = fragments;
1944: if (frag == null)
1945: break;
1946: fragments = frag.next;
1947: frag.emit(this );
1948: }
1949: if (locals != null && locals.container == null
1950: && !locals.isEmpty())
1951: locals.addToFrontOf(this );
1952: Attribute.assignConstants(this , cl);
1953: finalize_labels();
1954: }
1955:
1956: public final int getLength() {
1957: return 12 + getCodeLength() + 8 * exception_table_length
1958: + Attribute.getLengthAll(this );
1959: }
1960:
1961: public void write(DataOutputStream dstr) throws java.io.IOException {
1962: dstr.writeShort(max_stack);
1963: dstr.writeShort(max_locals);
1964: dstr.writeInt(PC);
1965: dstr.write(code, 0, PC);
1966:
1967: dstr.writeShort(exception_table_length);
1968: int count = exception_table_length;
1969: for (int i = 0; --count >= 0; i += 4) {
1970: dstr.writeShort(exception_table[i]);
1971: dstr.writeShort(exception_table[i + 1]);
1972: dstr.writeShort(exception_table[i + 2]);
1973: dstr.writeShort(exception_table[i + 3]);
1974: }
1975:
1976: Attribute.writeAll(this , dstr);
1977: }
1978:
1979: public void print(ClassTypeWriter dst) {
1980: dst.print("Attribute \"");
1981: dst.print(getName());
1982: dst.print("\", length:");
1983: dst.print(getLength());
1984: dst.print(", max_stack:");
1985: dst.print(max_stack);
1986: dst.print(", max_locals:");
1987: dst.print(max_locals);
1988: dst.print(", code_length:");
1989: int length = getCodeLength();
1990: dst.println(length);
1991: disAssemble(dst, 0, length);
1992: if (exception_table_length > 0) {
1993: dst.print("Exceptions (count: ");
1994: dst.print(exception_table_length);
1995: dst.println("):");
1996: int count = exception_table_length;
1997: for (int i = 0; --count >= 0; i += 4) {
1998: dst.print(" start: ");
1999: dst.print(exception_table[i] & 0xffff);
2000: dst.print(", end: ");
2001: dst.print(exception_table[i + 1] & 0xffff);
2002: dst.print(", handler: ");
2003: dst.print(exception_table[i + 2] & 0xffff);
2004: dst.print(", type: ");
2005: int catch_type_index = exception_table[i + 3] & 0xffff;
2006: if (catch_type_index == 0)
2007: dst.print("0 /* finally */");
2008: else {
2009: dst.printOptionalIndex(catch_type_index);
2010: dst.printConstantTersely(catch_type_index,
2011: ConstantPool.CLASS);
2012: }
2013: dst.println();
2014: }
2015: }
2016: dst.printAttributes(this );
2017: }
2018:
2019: public void disAssemble(ClassTypeWriter dst, int offset, int length) {
2020: boolean wide = false;
2021: for (int i = offset; i < length;) {
2022: int oldpc = i++;
2023: int op = code[oldpc] & 0xff;
2024: String str = Integer.toString(oldpc);
2025: int printConstant = 0;
2026: int j = str.length();
2027: while (++j <= 3)
2028: dst.print(' ');
2029: dst.print(str);
2030: dst.print(": ");
2031: // We do a rough binary partition of the opcodes.
2032: if (op < 120) {
2033: if (op < 87) {
2034: if (op < 3)
2035: print("nop;aconst_null;iconst_m1;", op, dst);
2036: else if (op < 9) {
2037: dst.print("iconst_");
2038: dst.print(op - 3);
2039: } else if (op < 16) // op >= 9 [lconst_0] && op <= 15 [dconst_1]
2040: {
2041: char typ;
2042: if (op < 11) {
2043: typ = 'l';
2044: op -= 9;
2045: } else if (op < 14) {
2046: typ = 'f';
2047: op -= 11;
2048: } else {
2049: typ = 'd';
2050: op -= 14;
2051: }
2052: dst.print(typ);
2053: dst.print("const_");
2054: dst.print(op);
2055: } else if (op < 21) {
2056: if (op < 18) // op >= 16 [bipush] && op <= 17 [sipush]
2057: {
2058: print("bipush ;sipush ;", op - 16, dst);
2059: int constant;
2060: if (op == 16)
2061: constant = code[i++];
2062: else {
2063: constant = (short) readUnsignedShort(i);
2064: i += 2;
2065: }
2066: dst.print(constant);
2067: } else // op >= 18 [ldc] && op <= 20 [ldc2_w]
2068: {
2069: printConstant = op == 18 ? 1 : 2;
2070: print("ldc;ldc_w;ldc2_w;", op - 18, dst);
2071: }
2072: } else // op >= 21 && op < 87
2073: {
2074: String load_or_store;
2075: if (op < 54) {
2076: load_or_store = "load";
2077: } else {
2078: load_or_store = "store";
2079: op -= (54 - 21);
2080: }
2081: int index; // -2 if array op; -1 if index follows
2082: if (op < 26) {
2083: index = -1;
2084: op -= 21;
2085: } else if (op < 46) {
2086: op -= 26;
2087: index = op % 4;
2088: op >>= 2;
2089: } else {
2090: index = -2;
2091: op -= 46;
2092: }
2093: dst.print("ilfdabcs".charAt(op));
2094: if (index == -2)
2095: dst.write('a');
2096: dst.print(load_or_store);
2097: if (index >= 0) {
2098: dst.write('_');
2099: dst.print(index);
2100: } else if (index == -1) {
2101: if (wide) {
2102: index = readUnsignedShort(i);
2103: i += 2;
2104: } else {
2105: index = code[i] & 0xff;
2106: i++;
2107: }
2108: wide = false;
2109: dst.print(' ');
2110: dst.print(index);
2111: }
2112: }
2113: } else // op >= 87 && op < 120
2114: {
2115: if (op < 96)
2116: print(
2117: "pop;pop2;dup;dup_x1;dup_x2;dup2;dup2_x1;dup2_x2;swap;",
2118: op - 87, dst);
2119: else // op >= 96 [iadd] && op <= 119 [dneg]
2120: {
2121: dst.print("ilfda".charAt((op - 96) % 4));
2122: print("add;sub;mul;div;rem;neg;",
2123: (op - 96) >> 2, dst);
2124: }
2125: }
2126: } else // op >= 120
2127: {
2128: if (op < 170) {
2129: if (op < 132) // op >= 120 [ishl] && op <= 131 [lxor]
2130: {
2131: dst.print((op & 1) == 0 ? 'i' : 'l');
2132: print("shl;shr;ushr;and;or;xor;",
2133: (op - 120) >> 1, dst);
2134: } else if (op == 132) // iinc
2135: {
2136: int var_index;
2137: int constant;
2138: dst.print("iinc");
2139: if (!wide) {
2140: var_index = 0xff & code[i++];
2141: constant = code[i++];
2142: } else {
2143: var_index = readUnsignedShort(i);
2144: i += 2;
2145: constant = (short) readUnsignedShort(i);
2146: i += 2;
2147: wide = false;
2148: }
2149: dst.print(' ');
2150: dst.print(var_index);
2151: dst.print(' ');
2152: dst.print(constant);
2153: } else if (op < 148) // op >= 133 [i2l] && op <= 147 [i2s]
2154: {
2155: dst.print("ilfdi".charAt((op - 133) / 3));
2156: dst.print('2');
2157: dst.print("lfdifdildilfbcs".charAt(op - 133));
2158: } else if (op < 153) // op >= 148 [lcmp] && op <= 152 [dcmpg]
2159: print("lcmp;fcmpl;fcmpg;dcmpl;dcmpg;",
2160: op - 148, dst);
2161: else if (op < 169) {
2162: if (op < 159) {
2163: dst.print("if");
2164: print("eq;ne;lt;ge;gt;le;", op - 153, dst);
2165: } else if (op < 167) {
2166: if (op < 165) {
2167: dst.print("if_icmp");
2168: } else {
2169: dst.print("if_acmp");
2170: op -= 165 - 159;
2171: }
2172: print("eq;ne;lt;ge;gt;le;", op - 159, dst);
2173: } else
2174: print("goto;jsr;", op - 167, dst);
2175: int delta = (short) readUnsignedShort(i);
2176: i += 2;
2177: dst.print(' ');
2178: dst.print(oldpc + delta);
2179: } else {
2180: int index;
2181: dst.print("ret ");
2182: if (wide) {
2183: index = readUnsignedShort(i);
2184: index += 2;
2185: } else {
2186: index = code[i] & 0xff;
2187: i++;
2188: }
2189: wide = false;
2190: dst.print(index);
2191: }
2192: } else {
2193: if (op < 172) // [tableswitch] or [lookupswitch]
2194: {
2195: i = (i + 3) & ~3; // skip 0-3 byte padding.
2196: int code_offset = readInt(i);
2197: i += 4;
2198: if (op == 170) {
2199: dst.print("tableswitch");
2200: int low = readInt(i);
2201: i += 4;
2202: int high = readInt(i);
2203: i += 4;
2204: dst.print(" low: ");
2205: dst.print(low);
2206: dst.print(" high: ");
2207: dst.print(high);
2208: dst.print(" default: ");
2209: dst.print(oldpc + code_offset);
2210: for (; low <= high; low++) {
2211: code_offset = readInt(i);
2212: i += 4;
2213: dst.println();
2214: dst.print(" ");
2215: dst.print(low);
2216: dst.print(": ");
2217: dst.print(oldpc + code_offset);
2218: }
2219: } else {
2220: dst.print("lookupswitch");
2221: int npairs = readInt(i);
2222: i += 4;
2223: dst.print(" npairs: ");
2224: dst.print(npairs);
2225: dst.print(" default: ");
2226: dst.print(oldpc + code_offset);
2227: while (--npairs >= 0) {
2228: int match = readInt(i);
2229: i += 4;
2230: code_offset = readInt(i);
2231: i += 4;
2232: dst.println();
2233: dst.print(" ");
2234: dst.print(match);
2235: dst.print(": ");
2236: dst.print(oldpc + code_offset);
2237: }
2238: }
2239: } else if (op < 178) // op >= 172 [ireturn] && op <= 177 [return]
2240: {
2241: if (op < 177)
2242: dst.print("ilfda".charAt(op - 172));
2243: dst.print("return");
2244: } else if (op < 182) // op >= 178 [getstatic] && op <= 181 [putfield]
2245: {
2246: print("getstatic;putstatic;getfield;putfield;",
2247: op - 178, dst);
2248: printConstant = 2;
2249: } else if (op < 185) // op >= 182 && op <= 185 [invoke*]
2250: {
2251: dst.print("invoke");
2252: print("virtual;special;static;", op - 182, dst);
2253: printConstant = 2;
2254: } else if (op == 185) // invokeinterface
2255: {
2256: dst.print("invokeinterface (");
2257: int index = readUnsignedShort(i);
2258: i += 2;
2259: int args = 0xff & code[i];
2260: i += 2;
2261: dst.print(args + " args)");
2262: dst.printConstantOperand(index);
2263: } else if (op < 196) {
2264: print(
2265: "186;new;newarray;anewarray;arraylength;athrow;checkcast;instanceof;monitorenter;monitorexit;",
2266: op - 186, dst);
2267: if (op == 187 || op == 189 || op == 192
2268: || op == 193)
2269: printConstant = 2;
2270: else if (op == 188) // newarray
2271: {
2272: int type = code[i++];
2273: dst.print(' ');
2274: if (type >= 4 && type <= 11)
2275: print(
2276: "boolean;char;float;double;byte;short;int;long;",
2277: type - 4, dst);
2278: else
2279: dst.print(type);
2280: }
2281:
2282: } else if (op == 196) // wide
2283: {
2284: dst.print("wide");
2285: wide = true;
2286: } else if (op == 197) {
2287: dst.print("multianewarray");
2288: int index = readUnsignedShort(i);
2289: i += 2;
2290: dst.printConstantOperand(index);
2291: int dims = 0xff & code[i++];
2292: dst.print(' ');
2293: dst.print(dims);
2294: } else if (op < 200) {
2295: print("ifnull;ifnonnull;", op - 198, dst);
2296: int delta = (short) readUnsignedShort(i);
2297: i += 2;
2298: dst.print(' ');
2299: dst.print(oldpc + delta);
2300: } else if (op < 202) {
2301: print("goto_w;jsr_w;", op - 200, dst);
2302: int delta = readInt(i);
2303: i += 4;
2304: dst.print(' ');
2305: dst.print(oldpc + delta);
2306: } else
2307: dst.print(op);
2308: }
2309: }
2310: if (printConstant > 0) {
2311: int index;
2312: if (printConstant == 1)
2313: index = 0xff & code[i++];
2314: else {
2315: index = readUnsignedShort(i);
2316: i += 2;
2317: }
2318: dst.printConstantOperand(index);
2319: }
2320: dst.println();
2321: }
2322: }
2323:
2324: private int readUnsignedShort(int offset) {
2325: return ((0xff & code[offset]) << 8) | (0xff & code[offset + 1]);
2326: }
2327:
2328: private int readInt(int offset) {
2329: return (readUnsignedShort(offset) << 16)
2330: | readUnsignedShort(offset + 2);
2331: }
2332:
2333: /*
2334: public saveStack (ClassType into)
2335: {
2336: Field[] flds = new Field[SP];
2337: while (SP > 0)
2338: {
2339: Field fld = ?;
2340: emitStore(fld);
2341: flds[SP...]
2342: }
2343: }
2344: */
2345:
2346: /* Print the i'th ';'-delimited substring of str on dst. */
2347: private void print(String str, int i, PrintWriter dst) {
2348: int last = 0;
2349: int pos = -1;
2350: for (; i >= 0; i--) {
2351: last = ++pos;
2352: pos = str.indexOf(';', last);
2353: }
2354: dst.write(str, last, pos - last);
2355: }
2356:
2357: /** Return an object encapsulating the type state of the JVM stack. */
2358: public Type[] saveStackTypeState(boolean clear) {
2359: if (SP == 0)
2360: return null;
2361: Type[] typeState = new Type[SP];
2362: System.arraycopy(stack_types, 0, typeState, 0, SP);
2363: if (clear)
2364: SP = 0;
2365: return typeState;
2366: }
2367:
2368: /** Restore a type state as saved by saveStackTypeState. */
2369: public void restoreStackTypeState(Type[] save) {
2370: if (save == null)
2371: SP = 0;
2372: else {
2373: SP = save.length;
2374: System.arraycopy(save, 0, stack_types, 0, SP);
2375: }
2376: }
2377:
2378: CodeFragment fragmentStack = null;
2379:
2380: public void beginFragment(boolean isHandler) {
2381: CodeFragment frag = new CodeFragment(this );
2382: frag.next = fragmentStack;
2383: fragmentStack = frag;
2384: frag.length = PC;
2385: frag.unreachable_save = unreachable_here;
2386: unreachable_here = false;
2387: if (isHandler)
2388: frag.handlerIndex = exception_table_length - 1;
2389: }
2390:
2391: public void endFragment() {
2392: CodeFragment frag = fragmentStack;
2393: fragmentStack = frag.next;
2394:
2395: frag.next = fragments;
2396: fragments = frag;
2397: int startPC = frag.length;
2398: frag.length = PC - startPC;
2399: frag.insns = new byte[frag.length];
2400: System.arraycopy(code, startPC, frag.insns, 0, frag.length);
2401: PC = startPC;
2402: unreachable_here = frag.unreachable_save;
2403:
2404: if (lines != null) {
2405: int l = 2 * lines.linenumber_count;
2406: int j = l;
2407: short[] linenumbers = lines.linenumber_table;
2408: while (j > 0 && linenumbers[j - 2] >= startPC)
2409: j -= 2;
2410: l -= j;
2411: if (l > 0) {
2412: short[] fraglines = new short[l];
2413: for (int i = 0; i < l; i += 2) {
2414: fraglines[i] = (short) ((linenumbers[j + i] & 0xffff) - startPC);
2415: fraglines[i + 1] = linenumbers[j + i + 1];
2416: }
2417: frag.linenumbers = fraglines;
2418: lines.linenumber_count = j >> 1;
2419: }
2420: }
2421: }
2422:
2423: /****************************************************************
2424: * Postcondition
2425: ****************************************************************/
2426:
2427: public void preparePostcondition(Field assertionEnabled,
2428: boolean hasPostCond) {
2429: this .assertionEnabled = assertionEnabled;
2430: if (hasPostCond)
2431: postconditionStart = new Label(this );
2432: }
2433:
2434: public void startPrecondition() {
2435: preconditionEnd = new Label(this );
2436: ifAssertionsDisabledGoto(assertionEnabled, preconditionEnd);
2437: }
2438:
2439: public void endPrecondition() {
2440: preconditionEnd.define(this );
2441: }
2442:
2443: public void startPostcondition() {
2444: postconditionEnd = new Label(this );
2445: postconditionStart.define(this );
2446: Type type = getMethod().getReturnType();
2447: if (!type.isVoid()) {
2448: // We expect the returned value on the stack.
2449: pushType(type);
2450: ifAssertionsDisabledGoto(assertionEnabled, postconditionEnd);
2451: resultVar = addLocal(type);
2452: emitStore(resultVar);
2453: } else
2454: ifAssertionsDisabledGoto(assertionEnabled, postconditionEnd);
2455: }
2456:
2457: public void pushRetType() {
2458: Type type = getMethod().getReturnType();
2459: if (!type.isVoid())
2460: pushType(type);
2461: }
2462:
2463: public void endPostcondition() {
2464: if (resultVar != null)
2465: loadResult();
2466: postconditionEnd.define(this );
2467: emitRealReturn();
2468: }
2469:
2470: public void loadResult() {
2471: emitLoad(resultVar);
2472: }
2473:
2474: boolean checkPostcondition() {
2475: if (postconditionStart == null)
2476: return false;
2477: emitGoto(postconditionStart);
2478: return true;
2479: }
2480:
2481: public void ifAssertionsDisabledGoto(Field assertionEnabled, Label l) {
2482: emitGetStatic(assertionEnabled);
2483: emitGotoIfIntEqZero(l);
2484: }
2485:
2486: private Label postconditionStart, postconditionEnd,
2487: preconditionEnd;
2488: private Variable resultVar;
2489: private Field assertionEnabled;
2490: }
|