0001: /*
0002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.asm;
0027:
0028: import sun.tools.java.*;
0029: import java.util.Enumeration;
0030: import java.io.IOException;
0031: import java.io.DataOutputStream;
0032: import java.io.PrintStream;
0033: import java.util.Vector; // JCOV
0034: import sun.tools.javac.*;
0035: import java.io.File;
0036: import java.io.BufferedInputStream;
0037: import java.io.DataInputStream;
0038: import java.io.FileInputStream;
0039: import java.io.FileNotFoundException;
0040: import java.io.FileOutputStream;
0041: import java.lang.String;
0042:
0043: // end JCOV
0044:
0045: /**
0046: * This class is used to assemble the bytecode instructions for a method.
0047: *
0048: * WARNING: The contents of this source file are not part of any
0049: * supported API. Code that depends on them does so at its own risk:
0050: * they are subject to change or removal without notice.
0051: *
0052: * @author Arthur van Hoff
0053: * @version 1.41, 08/19/97
0054: */
0055: public final class Assembler implements Constants {
0056: static final int NOTREACHED = 0;
0057: static final int REACHED = 1;
0058: static final int NEEDED = 2;
0059:
0060: Label first = new Label();
0061: Instruction last = first;
0062: int maxdepth;
0063: int maxvar;
0064: int maxpc;
0065:
0066: /**
0067: * Add an instruction
0068: */
0069: public void add(Instruction inst) {
0070: if (inst != null) {
0071: last.next = inst;
0072: last = inst;
0073: }
0074: }
0075:
0076: public void add(long where, int opc) {
0077: add(new Instruction(where, opc, null));
0078: }
0079:
0080: public void add(long where, int opc, Object obj) {
0081: add(new Instruction(where, opc, obj));
0082: }
0083:
0084: // JCOV
0085: public void add(long where, int opc, Object obj,
0086: boolean flagCondInverted) {
0087: add(new Instruction(where, opc, obj, flagCondInverted));
0088: }
0089:
0090: public void add(boolean flagNoCovered, long where, int opc,
0091: Object obj) {
0092: add(new Instruction(flagNoCovered, where, opc, obj));
0093: }
0094:
0095: public void add(long where, int opc, boolean flagNoCovered) {
0096: add(new Instruction(where, opc, flagNoCovered));
0097: }
0098:
0099: static Vector SourceClassList = new Vector();
0100:
0101: static Vector TmpCovTable = new Vector();
0102:
0103: static int[] JcovClassCountArray = new int[CT_LAST_KIND + 1];
0104:
0105: static String JcovMagicLine = "JCOV-DATA-FILE-VERSION: 2.0";
0106: static String JcovClassLine = "CLASS: ";
0107: static String JcovSrcfileLine = "SRCFILE: ";
0108: static String JcovTimestampLine = "TIMESTAMP: ";
0109: static String JcovDataLine = "DATA: ";
0110: static String JcovHeadingLine = "#kind\tcount";
0111:
0112: static int[] arrayModifiers = { M_PUBLIC, M_PRIVATE, M_PROTECTED,
0113: M_ABSTRACT, M_FINAL, M_INTERFACE };
0114: static int[] arrayModifiersOpc = { PUBLIC, PRIVATE, PROTECTED,
0115: ABSTRACT, FINAL, INTERFACE };
0116:
0117: //end JCOV
0118:
0119: /**
0120: * Optimize instructions and mark those that can be reached
0121: */
0122: void optimize(Environment env, Label lbl) {
0123: lbl.pc = REACHED;
0124:
0125: for (Instruction inst = lbl.next; inst != null; inst = inst.next) {
0126: switch (inst.pc) {
0127: case NOTREACHED:
0128: inst.optimize(env);
0129: inst.pc = REACHED;
0130: break;
0131: case REACHED:
0132: return;
0133: case NEEDED:
0134: break;
0135: }
0136:
0137: switch (inst.opc) {
0138: case opc_label:
0139: case opc_dead:
0140: if (inst.pc == REACHED) {
0141: inst.pc = NOTREACHED;
0142: }
0143: break;
0144:
0145: case opc_ifeq:
0146: case opc_ifne:
0147: case opc_ifgt:
0148: case opc_ifge:
0149: case opc_iflt:
0150: case opc_ifle:
0151: case opc_if_icmpeq:
0152: case opc_if_icmpne:
0153: case opc_if_icmpgt:
0154: case opc_if_icmpge:
0155: case opc_if_icmplt:
0156: case opc_if_icmple:
0157: case opc_if_acmpeq:
0158: case opc_if_acmpne:
0159: case opc_ifnull:
0160: case opc_ifnonnull:
0161: optimize(env, (Label) inst.value);
0162: break;
0163:
0164: case opc_goto:
0165: optimize(env, (Label) inst.value);
0166: return;
0167:
0168: case opc_jsr:
0169: optimize(env, (Label) inst.value);
0170: break;
0171:
0172: case opc_ret:
0173: case opc_return:
0174: case opc_ireturn:
0175: case opc_lreturn:
0176: case opc_freturn:
0177: case opc_dreturn:
0178: case opc_areturn:
0179: case opc_athrow:
0180: return;
0181:
0182: case opc_tableswitch:
0183: case opc_lookupswitch: {
0184: SwitchData sw = (SwitchData) inst.value;
0185: optimize(env, sw.defaultLabel);
0186: for (Enumeration e = sw.tab.elements(); e
0187: .hasMoreElements();) {
0188: optimize(env, (Label) e.nextElement());
0189: }
0190: return;
0191: }
0192:
0193: case opc_try: {
0194: TryData td = (TryData) inst.value;
0195: td.getEndLabel().pc = NEEDED;
0196: for (Enumeration e = td.catches.elements(); e
0197: .hasMoreElements();) {
0198: CatchData cd = (CatchData) e.nextElement();
0199: optimize(env, cd.getLabel());
0200: }
0201: break;
0202: }
0203: }
0204: }
0205: }
0206:
0207: /**
0208: * Eliminate instructions that are not reached
0209: */
0210: boolean eliminate() {
0211: boolean change = false;
0212: Instruction prev = first;
0213:
0214: for (Instruction inst = first.next; inst != null; inst = inst.next) {
0215: if (inst.pc != NOTREACHED) {
0216: prev.next = inst;
0217: prev = inst;
0218: inst.pc = NOTREACHED;
0219: } else {
0220: change = true;
0221: }
0222: }
0223: first.pc = NOTREACHED;
0224: prev.next = null;
0225: return change;
0226: }
0227:
0228: /**
0229: * Optimize the byte codes
0230: */
0231: public void optimize(Environment env) {
0232: //listing(System.out);
0233: do {
0234: // Figure out which instructions are reached
0235: optimize(env, first);
0236:
0237: // Eliminate instructions that are not reached
0238: } while (eliminate() && env.opt());
0239: }
0240:
0241: /**
0242: * Collect all constants into the constant table
0243: */
0244: public void collect(Environment env, MemberDefinition field,
0245: ConstantPool tab) {
0246: // Collect constants for arguments only
0247: // if a local variable table is generated
0248: if ((field != null) && env.debug_vars()) {
0249: if (field.getArguments() != null) {
0250: for (Enumeration e = field.getArguments().elements(); e
0251: .hasMoreElements();) {
0252: MemberDefinition f = (MemberDefinition) e
0253: .nextElement();
0254: tab.put(f.getName().toString());
0255: tab.put(f.getType().getTypeSignature());
0256: }
0257: }
0258: }
0259:
0260: // Collect constants from the instructions
0261: for (Instruction inst = first; inst != null; inst = inst.next) {
0262: inst.collect(tab);
0263: }
0264: }
0265:
0266: /**
0267: * Determine stack size, count local variables
0268: */
0269: void balance(Label lbl, int depth) {
0270: for (Instruction inst = lbl; inst != null; inst = inst.next) {
0271: //Environment.debugOutput(inst.toString() + ": " + depth + " => " +
0272: // (depth + inst.balance()));
0273: depth += inst.balance();
0274: if (depth < 0) {
0275: throw new CompilerError("stack under flow: "
0276: + inst.toString() + " = " + depth);
0277: }
0278: if (depth > maxdepth) {
0279: maxdepth = depth;
0280: }
0281: switch (inst.opc) {
0282: case opc_label:
0283: lbl = (Label) inst;
0284: if (inst.pc == REACHED) {
0285: if (lbl.depth != depth) {
0286: throw new CompilerError("stack depth error "
0287: + depth + "/" + lbl.depth + ": "
0288: + inst.toString());
0289: }
0290: return;
0291: }
0292: lbl.pc = REACHED;
0293: lbl.depth = depth;
0294: break;
0295:
0296: case opc_ifeq:
0297: case opc_ifne:
0298: case opc_ifgt:
0299: case opc_ifge:
0300: case opc_iflt:
0301: case opc_ifle:
0302: case opc_if_icmpeq:
0303: case opc_if_icmpne:
0304: case opc_if_icmpgt:
0305: case opc_if_icmpge:
0306: case opc_if_icmplt:
0307: case opc_if_icmple:
0308: case opc_if_acmpeq:
0309: case opc_if_acmpne:
0310: case opc_ifnull:
0311: case opc_ifnonnull:
0312: balance((Label) inst.value, depth);
0313: break;
0314:
0315: case opc_goto:
0316: balance((Label) inst.value, depth);
0317: return;
0318:
0319: case opc_jsr:
0320: balance((Label) inst.value, depth + 1);
0321: break;
0322:
0323: case opc_ret:
0324: case opc_return:
0325: case opc_ireturn:
0326: case opc_lreturn:
0327: case opc_freturn:
0328: case opc_dreturn:
0329: case opc_areturn:
0330: case opc_athrow:
0331: return;
0332:
0333: case opc_iload:
0334: case opc_fload:
0335: case opc_aload:
0336: case opc_istore:
0337: case opc_fstore:
0338: case opc_astore: {
0339: int v = ((inst.value instanceof Number) ? ((Number) inst.value)
0340: .intValue()
0341: : ((LocalVariable) inst.value).slot) + 1;
0342: if (v > maxvar)
0343: maxvar = v;
0344: break;
0345: }
0346:
0347: case opc_lload:
0348: case opc_dload:
0349: case opc_lstore:
0350: case opc_dstore: {
0351: int v = ((inst.value instanceof Number) ? ((Number) inst.value)
0352: .intValue()
0353: : ((LocalVariable) inst.value).slot) + 2;
0354: if (v > maxvar)
0355: maxvar = v;
0356: break;
0357: }
0358:
0359: case opc_iinc: {
0360: int v = ((int[]) inst.value)[0] + 1;
0361: if (v > maxvar)
0362: maxvar = v + 1;
0363: break;
0364: }
0365:
0366: case opc_tableswitch:
0367: case opc_lookupswitch: {
0368: SwitchData sw = (SwitchData) inst.value;
0369: balance(sw.defaultLabel, depth);
0370: for (Enumeration e = sw.tab.elements(); e
0371: .hasMoreElements();) {
0372: balance((Label) e.nextElement(), depth);
0373: }
0374: return;
0375: }
0376:
0377: case opc_try: {
0378: TryData td = (TryData) inst.value;
0379: for (Enumeration e = td.catches.elements(); e
0380: .hasMoreElements();) {
0381: CatchData cd = (CatchData) e.nextElement();
0382: balance(cd.getLabel(), depth + 1);
0383: }
0384: break;
0385: }
0386: }
0387: }
0388: }
0389:
0390: /**
0391: * Generate code
0392: */
0393: public void write(Environment env, DataOutputStream out,
0394: MemberDefinition field, ConstantPool tab)
0395: throws IOException {
0396: //listing(System.out);
0397:
0398: if ((field != null) && field.getArguments() != null) {
0399: int sum = 0;
0400: Vector v = field.getArguments();
0401: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0402: MemberDefinition f = ((MemberDefinition) e
0403: .nextElement());
0404: sum += f.getType().stackSize();
0405: }
0406: maxvar = sum;
0407: }
0408:
0409: // Make sure the stack balances. Also calculate maxvar and maxstack
0410: try {
0411: balance(first, 0);
0412: } catch (CompilerError e) {
0413: System.out.println("ERROR: " + e);
0414: listing(System.out);
0415: throw e;
0416: }
0417:
0418: // Assign PCs
0419: int pc = 0, nexceptions = 0;
0420: for (Instruction inst = first; inst != null; inst = inst.next) {
0421: inst.pc = pc;
0422: int sz = inst.size(tab);
0423: if (pc < 65536 && (pc + sz) >= 65536) {
0424: env.error(inst.where, "warn.method.too.long");
0425: }
0426: pc += sz;
0427:
0428: if (inst.opc == opc_try) {
0429: nexceptions += ((TryData) inst.value).catches.size();
0430: }
0431: }
0432:
0433: // Write header
0434: out.writeShort(maxdepth);
0435: out.writeShort(maxvar);
0436: out.writeInt(maxpc = pc);
0437:
0438: // Generate code
0439: for (Instruction inst = first.next; inst != null; inst = inst.next) {
0440: inst.write(out, tab);
0441: }
0442:
0443: // write exceptions
0444: out.writeShort(nexceptions);
0445: if (nexceptions > 0) {
0446: //listing(System.out);
0447: writeExceptions(env, out, tab, first, last);
0448: }
0449: }
0450:
0451: /**
0452: * Write the exceptions table
0453: */
0454: void writeExceptions(Environment env, DataOutputStream out,
0455: ConstantPool tab, Instruction first, Instruction last)
0456: throws IOException {
0457: for (Instruction inst = first; inst != last.next; inst = inst.next) {
0458: if (inst.opc == opc_try) {
0459: TryData td = (TryData) inst.value;
0460: writeExceptions(env, out, tab, inst.next, td
0461: .getEndLabel());
0462: for (Enumeration e = td.catches.elements(); e
0463: .hasMoreElements();) {
0464: CatchData cd = (CatchData) e.nextElement();
0465: //System.out.println("EXCEPTION: " + env.getSource() + ", pc=" + inst.pc + ", end=" + td.getEndLabel().pc + ", hdl=" + cd.getLabel().pc + ", tp=" + cd.getType());
0466: out.writeShort(inst.pc);
0467: out.writeShort(td.getEndLabel().pc);
0468: out.writeShort(cd.getLabel().pc);
0469: if (cd.getType() != null) {
0470: out.writeShort(tab.index(cd.getType()));
0471: } else {
0472: out.writeShort(0);
0473: }
0474: }
0475: inst = td.getEndLabel();
0476: }
0477: }
0478: }
0479:
0480: //JCOV
0481: /**
0482: * Write the coverage table
0483: */
0484: public void writeCoverageTable(Environment env, ClassDefinition c,
0485: DataOutputStream out, ConstantPool tab, long whereField)
0486: throws IOException {
0487: Vector TableLot = new Vector(); /* Coverage table */
0488: boolean begseg = false;
0489: boolean begmeth = false;
0490: long whereClass = ((SourceClass) c).getWhere();
0491: Vector whereTry = new Vector();
0492: int numberTry = 0;
0493: int count = 0;
0494:
0495: for (Instruction inst = first; inst != null; inst = inst.next) {
0496: long n = (inst.where >> WHEREOFFSETBITS);
0497: if (n > 0 && inst.opc != opc_label) {
0498: if (!begmeth) {
0499: if (whereClass == inst.where)
0500: TableLot.addElement(new Cover(CT_FIKT_METHOD,
0501: whereField, inst.pc));
0502: else
0503: TableLot.addElement(new Cover(CT_METHOD,
0504: whereField, inst.pc));
0505: count++;
0506: begmeth = true;
0507: }
0508: if (!begseg && !inst.flagNoCovered) {
0509: boolean findTry = false;
0510: for (Enumeration e = whereTry.elements(); e
0511: .hasMoreElements();) {
0512: if (((Long) (e.nextElement())).longValue() == inst.where) {
0513: findTry = true;
0514: break;
0515: }
0516: }
0517: if (!findTry) {
0518: TableLot.addElement(new Cover(CT_BLOCK,
0519: inst.where, inst.pc));
0520: count++;
0521: begseg = true;
0522: }
0523: }
0524: }
0525: switch (inst.opc) {
0526: case opc_label:
0527: begseg = false;
0528: break;
0529: case opc_ifeq:
0530: case opc_ifne:
0531: case opc_ifnull:
0532: case opc_ifnonnull:
0533: case opc_ifgt:
0534: case opc_ifge:
0535: case opc_iflt:
0536: case opc_ifle:
0537: case opc_if_icmpeq:
0538: case opc_if_icmpne:
0539: case opc_if_icmpgt:
0540: case opc_if_icmpge:
0541: case opc_if_icmplt:
0542: case opc_if_icmple:
0543: case opc_if_acmpeq:
0544: case opc_if_acmpne: {
0545: if (inst.flagCondInverted) {
0546: TableLot.addElement(new Cover(CT_BRANCH_TRUE,
0547: inst.where, inst.pc));
0548: TableLot.addElement(new Cover(CT_BRANCH_FALSE,
0549: inst.where, inst.pc));
0550: } else {
0551: TableLot.addElement(new Cover(CT_BRANCH_FALSE,
0552: inst.where, inst.pc));
0553: TableLot.addElement(new Cover(CT_BRANCH_TRUE,
0554: inst.where, inst.pc));
0555: }
0556: count += 2;
0557: begseg = false;
0558: break;
0559: }
0560:
0561: case opc_goto: {
0562: begseg = false;
0563: break;
0564: }
0565:
0566: case opc_ret:
0567: case opc_return:
0568: case opc_ireturn:
0569: case opc_lreturn:
0570: case opc_freturn:
0571: case opc_dreturn:
0572: case opc_areturn:
0573: case opc_athrow: {
0574: break;
0575: }
0576:
0577: case opc_try: {
0578: whereTry.addElement(new Long(inst.where));
0579: begseg = false;
0580: break;
0581: }
0582:
0583: case opc_tableswitch: {
0584: SwitchData sw = (SwitchData) inst.value;
0585: for (int i = sw.minValue; i <= sw.maxValue; i++) {
0586: TableLot.addElement(new Cover(CT_CASE, sw
0587: .whereCase(new Integer(i)), inst.pc));
0588: count++;
0589: }
0590: if (!sw.getDefault()) {
0591: TableLot.addElement(new Cover(CT_SWITH_WO_DEF,
0592: inst.where, inst.pc));
0593: count++;
0594: } else {
0595: TableLot.addElement(new Cover(CT_CASE, sw
0596: .whereCase("default"), inst.pc));
0597: count++;
0598: }
0599: begseg = false;
0600: break;
0601: }
0602: case opc_lookupswitch: {
0603: SwitchData sw = (SwitchData) inst.value;
0604: for (Enumeration e = sw.sortedKeys(); e
0605: .hasMoreElements();) {
0606: Integer v = (Integer) e.nextElement();
0607: TableLot.addElement(new Cover(CT_CASE, sw
0608: .whereCase(v), inst.pc));
0609: count++;
0610: }
0611: if (!sw.getDefault()) {
0612: TableLot.addElement(new Cover(CT_SWITH_WO_DEF,
0613: inst.where, inst.pc));
0614: count++;
0615: } else {
0616: TableLot.addElement(new Cover(CT_CASE, sw
0617: .whereCase("default"), inst.pc));
0618: count++;
0619: }
0620: begseg = false;
0621: break;
0622: }
0623: }
0624: }
0625: Cover Lot;
0626: long ln, pos;
0627:
0628: out.writeShort(count);
0629: for (int i = 0; i < count; i++) {
0630: Lot = (Cover) TableLot.elementAt(i);
0631: ln = (Lot.Addr >> WHEREOFFSETBITS);
0632: pos = (Lot.Addr << (64 - WHEREOFFSETBITS)) >> (64 - WHEREOFFSETBITS);
0633: out.writeShort(Lot.NumCommand);
0634: out.writeShort(Lot.Type);
0635: out.writeInt((int) ln);
0636: out.writeInt((int) pos);
0637:
0638: if (!(Lot.Type == CT_CASE && Lot.Addr == 0)) {
0639: JcovClassCountArray[Lot.Type]++;
0640: }
0641: }
0642:
0643: }
0644:
0645: /*
0646: * Increase count of methods for native methods
0647: */
0648:
0649: public void addNativeToJcovTab(Environment env, ClassDefinition c) {
0650: JcovClassCountArray[CT_METHOD]++;
0651: }
0652:
0653: /*
0654: * Create class jcov element
0655: */
0656:
0657: private String createClassJcovElement(Environment env,
0658: ClassDefinition c) {
0659: String SourceClass = (Type.mangleInnerType((c
0660: .getClassDeclaration()).getName())).toString();
0661: String ConvSourceClass;
0662: String classJcovLine;
0663:
0664: SourceClassList.addElement(SourceClass);
0665: ConvSourceClass = SourceClass.replace('.', '/');
0666: classJcovLine = JcovClassLine + ConvSourceClass;
0667:
0668: classJcovLine = classJcovLine + " [";
0669: String blank = "";
0670:
0671: for (int i = 0; i < arrayModifiers.length; i++) {
0672: if ((c.getModifiers() & arrayModifiers[i]) != 0) {
0673: classJcovLine = classJcovLine + blank
0674: + opNames[arrayModifiersOpc[i]];
0675: blank = " ";
0676: }
0677: }
0678: classJcovLine = classJcovLine + "]";
0679:
0680: return classJcovLine;
0681: }
0682:
0683: /*
0684: * generate coverage data
0685: */
0686:
0687: public void GenVecJCov(Environment env, ClassDefinition c, long Time) {
0688: String SourceFile = ((SourceClass) c).getAbsoluteName();
0689:
0690: TmpCovTable.addElement(createClassJcovElement(env, c));
0691: TmpCovTable.addElement(JcovSrcfileLine + SourceFile);
0692: TmpCovTable.addElement(JcovTimestampLine + Time);
0693: TmpCovTable.addElement(JcovDataLine + "A"); // data format
0694: TmpCovTable.addElement(JcovHeadingLine);
0695:
0696: for (int i = CT_FIRST_KIND; i <= CT_LAST_KIND; i++) {
0697: if (JcovClassCountArray[i] != 0) {
0698: TmpCovTable.addElement(new String(i + "\t"
0699: + JcovClassCountArray[i]));
0700: JcovClassCountArray[i] = 0;
0701: }
0702: }
0703: }
0704:
0705: /*
0706: * generate file of coverage data
0707: */
0708:
0709: public void GenJCov(Environment env) {
0710:
0711: try {
0712: File outFile = env.getcovFile();
0713: if (outFile.exists()) {
0714: DataInputStream JCovd = new DataInputStream(
0715: new BufferedInputStream(new FileInputStream(
0716: outFile)));
0717: String CurrLine = null;
0718: boolean first = true;
0719: String Class;
0720:
0721: CurrLine = JCovd.readLine();
0722: if ((CurrLine != null)
0723: && CurrLine.startsWith(JcovMagicLine)) {
0724: // this is a good Jcov file
0725:
0726: while ((CurrLine = JCovd.readLine()) != null) {
0727: if (CurrLine.startsWith(JcovClassLine)) {
0728: first = true;
0729: for (Enumeration e = SourceClassList
0730: .elements(); e.hasMoreElements();) {
0731: String clsName = CurrLine
0732: .substring(JcovClassLine
0733: .length());
0734: int idx = clsName.indexOf(' ');
0735:
0736: if (idx != -1) {
0737: clsName = clsName.substring(0, idx);
0738: }
0739: Class = (String) e.nextElement();
0740: if (Class.compareTo(clsName) == 0) {
0741: first = false;
0742: break;
0743: }
0744: }
0745: }
0746: if (first) // re-write old class
0747: TmpCovTable.addElement(CurrLine);
0748: }
0749: }
0750: JCovd.close();
0751: }
0752: PrintStream CovFile = new PrintStream(new DataOutputStream(
0753: new FileOutputStream(outFile)));
0754: CovFile.println(JcovMagicLine);
0755: for (Enumeration e = TmpCovTable.elements(); e
0756: .hasMoreElements();) {
0757: CovFile.println(e.nextElement());
0758: }
0759: CovFile.close();
0760: } catch (FileNotFoundException e) {
0761: System.out.println("ERROR: " + e);
0762: } catch (IOException e) {
0763: System.out.println("ERROR: " + e);
0764: }
0765: }
0766:
0767: // end JCOV
0768:
0769: /**
0770: * Write the linenumber table
0771: */
0772: public void writeLineNumberTable(Environment env,
0773: DataOutputStream out, ConstantPool tab) throws IOException {
0774: long ln = -1;
0775: int count = 0;
0776:
0777: for (Instruction inst = first; inst != null; inst = inst.next) {
0778: long n = (inst.where >> WHEREOFFSETBITS);
0779: if ((n > 0) && (ln != n)) {
0780: ln = n;
0781: count++;
0782: }
0783: }
0784:
0785: ln = -1;
0786: out.writeShort(count);
0787: for (Instruction inst = first; inst != null; inst = inst.next) {
0788: long n = (inst.where >> WHEREOFFSETBITS);
0789: if ((n > 0) && (ln != n)) {
0790: ln = n;
0791: out.writeShort(inst.pc);
0792: out.writeShort((int) ln);
0793: //System.out.println("pc = " + inst.pc + ", ln = " + ln);
0794: }
0795: }
0796: }
0797:
0798: /**
0799: * Figure out when registers contain a legal value. This is done
0800: * using a simple data flow algorithm. This information is later used
0801: * to generate the local variable table.
0802: */
0803: void flowFields(Environment env, Label lbl,
0804: MemberDefinition locals[]) {
0805: if (lbl.locals != null) {
0806: // Been here before. Erase any conflicts.
0807: MemberDefinition f[] = lbl.locals;
0808: for (int i = 0; i < maxvar; i++) {
0809: if (f[i] != locals[i]) {
0810: f[i] = null;
0811: }
0812: }
0813: return;
0814: }
0815:
0816: // Remember the set of active registers at this point
0817: lbl.locals = new MemberDefinition[maxvar];
0818: System.arraycopy(locals, 0, lbl.locals, 0, maxvar);
0819:
0820: MemberDefinition newlocals[] = new MemberDefinition[maxvar];
0821: System.arraycopy(locals, 0, newlocals, 0, maxvar);
0822: locals = newlocals;
0823:
0824: for (Instruction inst = lbl.next; inst != null; inst = inst.next) {
0825: switch (inst.opc) {
0826: case opc_istore:
0827: case opc_istore_0:
0828: case opc_istore_1:
0829: case opc_istore_2:
0830: case opc_istore_3:
0831: case opc_fstore:
0832: case opc_fstore_0:
0833: case opc_fstore_1:
0834: case opc_fstore_2:
0835: case opc_fstore_3:
0836: case opc_astore:
0837: case opc_astore_0:
0838: case opc_astore_1:
0839: case opc_astore_2:
0840: case opc_astore_3:
0841: case opc_lstore:
0842: case opc_lstore_0:
0843: case opc_lstore_1:
0844: case opc_lstore_2:
0845: case opc_lstore_3:
0846: case opc_dstore:
0847: case opc_dstore_0:
0848: case opc_dstore_1:
0849: case opc_dstore_2:
0850: case opc_dstore_3:
0851: if (inst.value instanceof LocalVariable) {
0852: LocalVariable v = (LocalVariable) inst.value;
0853: locals[v.slot] = v.field;
0854: }
0855: break;
0856:
0857: case opc_label:
0858: flowFields(env, (Label) inst, locals);
0859: return;
0860:
0861: case opc_ifeq:
0862: case opc_ifne:
0863: case opc_ifgt:
0864: case opc_ifge:
0865: case opc_iflt:
0866: case opc_ifle:
0867: case opc_if_icmpeq:
0868: case opc_if_icmpne:
0869: case opc_if_icmpgt:
0870: case opc_if_icmpge:
0871: case opc_if_icmplt:
0872: case opc_if_icmple:
0873: case opc_if_acmpeq:
0874: case opc_if_acmpne:
0875: case opc_ifnull:
0876: case opc_ifnonnull:
0877: case opc_jsr:
0878: flowFields(env, (Label) inst.value, locals);
0879: break;
0880:
0881: case opc_goto:
0882: flowFields(env, (Label) inst.value, locals);
0883: return;
0884:
0885: case opc_return:
0886: case opc_ireturn:
0887: case opc_lreturn:
0888: case opc_freturn:
0889: case opc_dreturn:
0890: case opc_areturn:
0891: case opc_athrow:
0892: case opc_ret:
0893: return;
0894:
0895: case opc_tableswitch:
0896: case opc_lookupswitch: {
0897: SwitchData sw = (SwitchData) inst.value;
0898: flowFields(env, sw.defaultLabel, locals);
0899: for (Enumeration e = sw.tab.elements(); e
0900: .hasMoreElements();) {
0901: flowFields(env, (Label) e.nextElement(), locals);
0902: }
0903: return;
0904: }
0905:
0906: case opc_try: {
0907: Vector catches = ((TryData) inst.value).catches;
0908: for (Enumeration e = catches.elements(); e
0909: .hasMoreElements();) {
0910: CatchData cd = (CatchData) e.nextElement();
0911: flowFields(env, cd.getLabel(), locals);
0912: }
0913: break;
0914: }
0915: }
0916: }
0917: }
0918:
0919: /**
0920: * Write the local variable table. The necessary constants have already been
0921: * added to the constant table by the collect() method. The flowFields method
0922: * is used to determine which variables are alive at each pc.
0923: */
0924: public void writeLocalVariableTable(Environment env,
0925: MemberDefinition field, DataOutputStream out,
0926: ConstantPool tab) throws IOException {
0927: MemberDefinition locals[] = new MemberDefinition[maxvar];
0928: int i = 0;
0929:
0930: // Initialize arguments
0931: if ((field != null) && (field.getArguments() != null)) {
0932: int reg = 0;
0933: Vector v = field.getArguments();
0934: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0935: MemberDefinition f = ((MemberDefinition) e
0936: .nextElement());
0937: locals[reg] = f;
0938: reg += f.getType().stackSize();
0939: }
0940: }
0941:
0942: flowFields(env, first, locals);
0943: LocalVariableTable lvtab = new LocalVariableTable();
0944:
0945: // Initialize arguments again
0946: for (i = 0; i < maxvar; i++)
0947: locals[i] = null;
0948: if ((field != null) && (field.getArguments() != null)) {
0949: int reg = 0;
0950: Vector v = field.getArguments();
0951: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0952: MemberDefinition f = ((MemberDefinition) e
0953: .nextElement());
0954: locals[reg] = f;
0955: lvtab.define(f, reg, 0, maxpc);
0956: reg += f.getType().stackSize();
0957: }
0958: }
0959:
0960: int pcs[] = new int[maxvar];
0961:
0962: for (Instruction inst = first; inst != null; inst = inst.next) {
0963: switch (inst.opc) {
0964: case opc_istore:
0965: case opc_istore_0:
0966: case opc_istore_1:
0967: case opc_istore_2:
0968: case opc_istore_3:
0969: case opc_fstore:
0970: case opc_fstore_0:
0971: case opc_fstore_1:
0972: case opc_fstore_2:
0973: case opc_fstore_3:
0974: case opc_astore:
0975: case opc_astore_0:
0976: case opc_astore_1:
0977: case opc_astore_2:
0978: case opc_astore_3:
0979: case opc_lstore:
0980: case opc_lstore_0:
0981: case opc_lstore_1:
0982: case opc_lstore_2:
0983: case opc_lstore_3:
0984: case opc_dstore:
0985: case opc_dstore_0:
0986: case opc_dstore_1:
0987: case opc_dstore_2:
0988: case opc_dstore_3:
0989: if (inst.value instanceof LocalVariable) {
0990: LocalVariable v = (LocalVariable) inst.value;
0991: int pc = (inst.next != null) ? inst.next.pc
0992: : inst.pc;
0993: if (locals[v.slot] != null) {
0994: lvtab.define(locals[v.slot], v.slot,
0995: pcs[v.slot], pc);
0996: }
0997: pcs[v.slot] = pc;
0998: locals[v.slot] = v.field;
0999: }
1000: break;
1001:
1002: case opc_label: {
1003: // flush previous labels
1004: for (i = 0; i < maxvar; i++) {
1005: if (locals[i] != null) {
1006: lvtab.define(locals[i], i, pcs[i], inst.pc);
1007: }
1008: }
1009: // init new labels
1010: int pc = inst.pc;
1011: MemberDefinition[] labelLocals = ((Label) inst).locals;
1012: if (labelLocals == null) { // unreachable code??
1013: for (i = 0; i < maxvar; i++)
1014: locals[i] = null;
1015: } else {
1016: System.arraycopy(labelLocals, 0, locals, 0, maxvar);
1017: }
1018: for (i = 0; i < maxvar; i++) {
1019: pcs[i] = pc;
1020: }
1021: break;
1022: }
1023: }
1024: }
1025:
1026: // flush remaining labels
1027: for (i = 0; i < maxvar; i++) {
1028: if (locals[i] != null) {
1029: lvtab.define(locals[i], i, pcs[i], maxpc);
1030: }
1031: }
1032:
1033: // write the local variable table
1034: lvtab.write(env, out, tab);
1035: }
1036:
1037: /**
1038: * Return true if empty
1039: */
1040: public boolean empty() {
1041: return first == last;
1042: }
1043:
1044: /**
1045: * Print the byte codes
1046: */
1047: public void listing(PrintStream out) {
1048: out.println("-- listing --");
1049: for (Instruction inst = first; inst != null; inst = inst.next) {
1050: out.println(inst.toString());
1051: }
1052: }
1053: }
|