0001: /*
0002: * Copyright 1999-2006 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 com.sun.tools.javac.jvm;
0027:
0028: import java.io.*;
0029: import java.util.*;
0030: import java.util.Set;
0031: import java.util.HashSet;
0032:
0033: import javax.tools.JavaFileManager;
0034: import javax.tools.FileObject;
0035: import javax.tools.JavaFileObject;
0036:
0037: import com.sun.tools.javac.code.*;
0038: import com.sun.tools.javac.code.Symbol.*;
0039: import com.sun.tools.javac.code.Type.*;
0040: import com.sun.tools.javac.util.*;
0041: import com.sun.tools.javac.util.List;
0042:
0043: import static com.sun.tools.javac.code.BoundKind.*;
0044: import static com.sun.tools.javac.code.Flags.*;
0045: import static com.sun.tools.javac.code.Kinds.*;
0046: import static com.sun.tools.javac.code.TypeTags.*;
0047: import static com.sun.tools.javac.jvm.UninitializedType.*;
0048: import static javax.tools.StandardLocation.CLASS_OUTPUT;
0049:
0050: /** This class provides operations to map an internal symbol table graph
0051: * rooted in a ClassSymbol into a classfile.
0052: *
0053: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
0054: * you write code that depends on this, you do so at your own risk.
0055: * This code and its internal interfaces are subject to change or
0056: * deletion without notice.</b>
0057: */
0058: @Version("@(#)ClassWriter.java 1.131 07/07/20")
0059: public class ClassWriter extends ClassFile {
0060: protected static final Context.Key<ClassWriter> classWriterKey = new Context.Key<ClassWriter>();
0061:
0062: private final Symtab syms;
0063:
0064: private final Options options;
0065:
0066: /** Switch: verbose output.
0067: */
0068: private boolean verbose;
0069:
0070: /** Switch: scrable private names.
0071: */
0072: private boolean scramble;
0073:
0074: /** Switch: scrable private names.
0075: */
0076: private boolean scrambleAll;
0077:
0078: /** Switch: retrofit mode.
0079: */
0080: private boolean retrofit;
0081:
0082: /** Switch: emit source file attribute.
0083: */
0084: private boolean emitSourceFile;
0085:
0086: /** Switch: generate CharacterRangeTable attribute.
0087: */
0088: private boolean genCrt;
0089:
0090: /** Switch: describe the generated stackmap
0091: */
0092: boolean debugstackmap;
0093:
0094: /**
0095: * Target class version.
0096: */
0097: private Target target;
0098:
0099: /**
0100: * Source language version.
0101: */
0102: private Source source;
0103:
0104: /** Type utilities. */
0105: private Types types;
0106:
0107: /** The initial sizes of the data and constant pool buffers.
0108: * sizes are increased when buffers get full.
0109: */
0110: static final int DATA_BUF_SIZE = 0x0fff0;
0111: static final int POOL_BUF_SIZE = 0x1fff0;
0112:
0113: /** An output buffer for member info.
0114: */
0115: ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
0116:
0117: /** An output buffer for the constant pool.
0118: */
0119: ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
0120:
0121: /** An output buffer for type signatures.
0122: */
0123: ByteBuffer sigbuf = new ByteBuffer();
0124:
0125: /** The constant pool.
0126: */
0127: Pool pool;
0128:
0129: /** The inner classes to be written, as a set.
0130: */
0131: Set<ClassSymbol> innerClasses;
0132:
0133: /** The inner classes to be written, as a queue where
0134: * enclosing classes come first.
0135: */
0136: ListBuffer<ClassSymbol> innerClassesQueue;
0137:
0138: /** The log to use for verbose output.
0139: */
0140: private final Log log;
0141:
0142: /** The name table. */
0143: private final Name.Table names;
0144:
0145: /** Access to files. */
0146: private final JavaFileManager fileManager;
0147:
0148: /** The tags and constants used in compressed stackmap. */
0149: static final int SAME_FRAME_SIZE = 64;
0150: static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
0151: static final int SAME_FRAME_EXTENDED = 251;
0152: static final int FULL_FRAME = 255;
0153: static final int MAX_LOCAL_LENGTH_DIFF = 4;
0154:
0155: /** Get the ClassWriter instance for this context. */
0156: public static ClassWriter instance(Context context) {
0157: ClassWriter instance = context.get(classWriterKey);
0158: if (instance == null)
0159: instance = new ClassWriter(context);
0160: return instance;
0161: }
0162:
0163: /** Construct a class writer, given an options table.
0164: */
0165: private ClassWriter(Context context) {
0166: context.put(classWriterKey, this );
0167:
0168: log = Log.instance(context);
0169: names = Name.Table.instance(context);
0170: syms = Symtab.instance(context);
0171: options = Options.instance(context);
0172: target = Target.instance(context);
0173: source = Source.instance(context);
0174: types = Types.instance(context);
0175: fileManager = context.get(JavaFileManager.class);
0176:
0177: verbose = options.get("-verbose") != null;
0178: scramble = options.get("-scramble") != null;
0179: scrambleAll = options.get("-scrambleAll") != null;
0180: retrofit = options.get("-retrofit") != null;
0181: genCrt = options.get("-Xjcov") != null;
0182: debugstackmap = options.get("debugstackmap") != null;
0183:
0184: emitSourceFile = options.get("-g:") == null
0185: || options.get("-g:source") != null;
0186:
0187: String dumpModFlags = options.get("dumpmodifiers");
0188: dumpClassModifiers = (dumpModFlags != null && dumpModFlags
0189: .indexOf('c') != -1);
0190: dumpFieldModifiers = (dumpModFlags != null && dumpModFlags
0191: .indexOf('f') != -1);
0192: dumpInnerClassModifiers = (dumpModFlags != null && dumpModFlags
0193: .indexOf('i') != -1);
0194: dumpMethodModifiers = (dumpModFlags != null && dumpModFlags
0195: .indexOf('m') != -1);
0196: }
0197:
0198: /******************************************************************
0199: * Diagnostics: dump generated class names and modifiers
0200: ******************************************************************/
0201:
0202: /** Value of option 'dumpmodifiers' is a string
0203: * indicating which modifiers should be dumped for debugging:
0204: * 'c' -- classes
0205: * 'f' -- fields
0206: * 'i' -- innerclass attributes
0207: * 'm' -- methods
0208: * For example, to dump everything:
0209: * javac -XDdumpmodifiers=cifm MyProg.java
0210: */
0211: private final boolean dumpClassModifiers; // -XDdumpmodifiers=c
0212: private final boolean dumpFieldModifiers; // -XDdumpmodifiers=f
0213: private final boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
0214: private final boolean dumpMethodModifiers; // -XDdumpmodifiers=m
0215:
0216: /** Return flags as a string, separated by " ".
0217: */
0218: public static String flagNames(long flags) {
0219: StringBuffer sbuf = new StringBuffer();
0220: int i = 0;
0221: long f = flags & StandardFlags;
0222: while (f != 0) {
0223: if ((f & 1) != 0)
0224: sbuf.append(" " + flagName[i]);
0225: f = f >> 1;
0226: i++;
0227: }
0228: return sbuf.toString();
0229: }
0230:
0231: //where
0232: private final static String[] flagName = { "PUBLIC", "PRIVATE",
0233: "PROTECTED", "STATIC", "FINAL", "SUPER", "VOLATILE",
0234: "TRANSIENT", "NATIVE", "INTERFACE", "ABSTRACT", "STRICTFP" };
0235:
0236: /******************************************************************
0237: * Output routines
0238: ******************************************************************/
0239:
0240: /** Write a character into given byte buffer;
0241: * byte buffer will not be grown.
0242: */
0243: void putChar(ByteBuffer buf, int op, int x) {
0244: buf.elems[op] = (byte) ((x >> 8) & 0xFF);
0245: buf.elems[op + 1] = (byte) ((x) & 0xFF);
0246: }
0247:
0248: /** Write an integer into given byte buffer;
0249: * byte buffer will not be grown.
0250: */
0251: void putInt(ByteBuffer buf, int adr, int x) {
0252: buf.elems[adr] = (byte) ((x >> 24) & 0xFF);
0253: buf.elems[adr + 1] = (byte) ((x >> 16) & 0xFF);
0254: buf.elems[adr + 2] = (byte) ((x >> 8) & 0xFF);
0255: buf.elems[adr + 3] = (byte) ((x) & 0xFF);
0256: }
0257:
0258: /******************************************************************
0259: * Signature Generation
0260: ******************************************************************/
0261:
0262: /** Assemble signature of given type in string buffer.
0263: */
0264: void assembleSig(Type type) {
0265: switch (type.tag) {
0266: case BYTE:
0267: sigbuf.appendByte('B');
0268: break;
0269: case SHORT:
0270: sigbuf.appendByte('S');
0271: break;
0272: case CHAR:
0273: sigbuf.appendByte('C');
0274: break;
0275: case INT:
0276: sigbuf.appendByte('I');
0277: break;
0278: case LONG:
0279: sigbuf.appendByte('J');
0280: break;
0281: case FLOAT:
0282: sigbuf.appendByte('F');
0283: break;
0284: case DOUBLE:
0285: sigbuf.appendByte('D');
0286: break;
0287: case BOOLEAN:
0288: sigbuf.appendByte('Z');
0289: break;
0290: case VOID:
0291: sigbuf.appendByte('V');
0292: break;
0293: case CLASS:
0294: sigbuf.appendByte('L');
0295: assembleClassSig(type);
0296: sigbuf.appendByte(';');
0297: break;
0298: case ARRAY:
0299: ArrayType at = (ArrayType) type;
0300: sigbuf.appendByte('[');
0301: assembleSig(at.elemtype);
0302: break;
0303: case METHOD:
0304: MethodType mt = (MethodType) type;
0305: sigbuf.appendByte('(');
0306: assembleSig(mt.argtypes);
0307: sigbuf.appendByte(')');
0308: assembleSig(mt.restype);
0309: if (hasTypeVar(mt.thrown)) {
0310: for (List<Type> l = mt.thrown; l.nonEmpty(); l = l.tail) {
0311: sigbuf.appendByte('^');
0312: assembleSig(l.head);
0313: }
0314: }
0315: break;
0316: case WILDCARD: {
0317: WildcardType ta = (WildcardType) type;
0318: switch (ta.kind) {
0319: case SUPER:
0320: sigbuf.appendByte('-');
0321: assembleSig(ta.type);
0322: break;
0323: case EXTENDS:
0324: sigbuf.appendByte('+');
0325: assembleSig(ta.type);
0326: break;
0327: case UNBOUND:
0328: sigbuf.appendByte('*');
0329: break;
0330: default:
0331: throw new AssertionError(ta.kind);
0332: }
0333: break;
0334: }
0335: case TYPEVAR:
0336: sigbuf.appendByte('T');
0337: sigbuf.appendName(type.tsym.name);
0338: sigbuf.appendByte(';');
0339: break;
0340: case FORALL:
0341: ForAll ft = (ForAll) type;
0342: assembleParamsSig(ft.tvars);
0343: assembleSig(ft.qtype);
0344: break;
0345: case UNINITIALIZED_THIS:
0346: case UNINITIALIZED_OBJECT:
0347: // we don't yet have a spec for uninitialized types in the
0348: // local variable table
0349: assembleSig(types.erasure(((UninitializedType) type).qtype));
0350: break;
0351: default:
0352: throw new AssertionError("typeSig " + type.tag);
0353: }
0354: }
0355:
0356: boolean hasTypeVar(List<Type> l) {
0357: while (l.nonEmpty()) {
0358: if (l.head.tag == TypeTags.TYPEVAR)
0359: return true;
0360: l = l.tail;
0361: }
0362: return false;
0363: }
0364:
0365: void assembleClassSig(Type type) {
0366: ClassType ct = (ClassType) type;
0367: ClassSymbol c = (ClassSymbol) ct.tsym;
0368: enterInner(c);
0369: Type outer = ct.getEnclosingType();
0370: if (outer.allparams().nonEmpty()) {
0371: boolean rawOuter = c.owner.kind == MTH || // either a local class
0372: c.name == names.empty; // or anonymous
0373: assembleClassSig(rawOuter ? types.erasure(outer) : outer);
0374: sigbuf.appendByte('.');
0375: assert c.flatname.startsWith(c.owner.enclClass().flatname);
0376: sigbuf.appendName(rawOuter ? c.flatname.subName(c.owner
0377: .enclClass().flatname.len + 1, c.flatname.len)
0378: : c.name);
0379: } else {
0380: sigbuf.appendBytes(externalize(c.flatname));
0381: }
0382: if (ct.getTypeArguments().nonEmpty()) {
0383: sigbuf.appendByte('<');
0384: assembleSig(ct.getTypeArguments());
0385: sigbuf.appendByte('>');
0386: }
0387: }
0388:
0389: void assembleSig(List<Type> types) {
0390: for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail)
0391: assembleSig(ts.head);
0392: }
0393:
0394: void assembleParamsSig(List<Type> typarams) {
0395: sigbuf.appendByte('<');
0396: for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) {
0397: TypeVar tvar = (TypeVar) ts.head;
0398: sigbuf.appendName(tvar.tsym.name);
0399: List<Type> bounds = types.getBounds(tvar);
0400: if ((bounds.head.tsym.flags() & INTERFACE) != 0) {
0401: sigbuf.appendByte(':');
0402: }
0403: for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) {
0404: sigbuf.appendByte(':');
0405: assembleSig(l.head);
0406: }
0407: }
0408: sigbuf.appendByte('>');
0409: }
0410:
0411: /** Return signature of given type
0412: */
0413: Name typeSig(Type type) {
0414: assert sigbuf.length == 0;
0415: //- System.out.println(" ? " + type);
0416: assembleSig(type);
0417: Name n = sigbuf.toName(names);
0418: sigbuf.reset();
0419: //- System.out.println(" " + n);
0420: return n;
0421: }
0422:
0423: /** Given a type t, return the extended class name of its erasure in
0424: * external representation.
0425: */
0426: public Name xClassName(Type t) {
0427: if (t.tag == CLASS) {
0428: return names.fromUtf(externalize(t.tsym.flatName()));
0429: } else if (t.tag == ARRAY) {
0430: return typeSig(types.erasure(t));
0431: } else {
0432: throw new AssertionError("xClassName");
0433: }
0434: }
0435:
0436: /******************************************************************
0437: * Writing the Constant Pool
0438: ******************************************************************/
0439:
0440: /** Thrown when the constant pool is over full.
0441: */
0442: public static class PoolOverflow extends Exception {
0443: private static final long serialVersionUID = 0;
0444:
0445: public PoolOverflow() {
0446: }
0447: }
0448:
0449: public static class StringOverflow extends Exception {
0450: private static final long serialVersionUID = 0;
0451: public final String value;
0452:
0453: public StringOverflow(String s) {
0454: value = s;
0455: }
0456: }
0457:
0458: /** Write constant pool to pool buffer.
0459: * Note: during writing, constant pool
0460: * might grow since some parts of constants still need to be entered.
0461: */
0462: void writePool(Pool pool) throws PoolOverflow, StringOverflow {
0463: int poolCountIdx = poolbuf.length;
0464: poolbuf.appendChar(0);
0465: int i = 1;
0466: while (i < pool.pp) {
0467: Object value = pool.pool[i];
0468: assert value != null;
0469: if (value instanceof Pool.Method)
0470: value = ((Pool.Method) value).m;
0471: else if (value instanceof Pool.Variable)
0472: value = ((Pool.Variable) value).v;
0473:
0474: if (value instanceof MethodSymbol) {
0475: MethodSymbol m = (MethodSymbol) value;
0476: poolbuf
0477: .appendByte((m.owner.flags() & INTERFACE) != 0 ? CONSTANT_InterfaceMethodref
0478: : CONSTANT_Methodref);
0479: poolbuf.appendChar(pool.put(m.owner));
0480: poolbuf.appendChar(pool.put(nameType(m)));
0481: } else if (value instanceof VarSymbol) {
0482: VarSymbol v = (VarSymbol) value;
0483: poolbuf.appendByte(CONSTANT_Fieldref);
0484: poolbuf.appendChar(pool.put(v.owner));
0485: poolbuf.appendChar(pool.put(nameType(v)));
0486: } else if (value instanceof Name) {
0487: poolbuf.appendByte(CONSTANT_Utf8);
0488: byte[] bs = ((Name) value).toUtf();
0489: poolbuf.appendChar(bs.length);
0490: poolbuf.appendBytes(bs, 0, bs.length);
0491: if (bs.length > Pool.MAX_STRING_LENGTH)
0492: throw new StringOverflow(value.toString());
0493: } else if (value instanceof ClassSymbol) {
0494: ClassSymbol c = (ClassSymbol) value;
0495: if (c.owner.kind == TYP)
0496: pool.put(c.owner);
0497: poolbuf.appendByte(CONSTANT_Class);
0498: if (c.type.tag == ARRAY) {
0499: poolbuf.appendChar(pool.put(typeSig(c.type)));
0500: } else {
0501: poolbuf.appendChar(pool.put(names
0502: .fromUtf(externalize(c.flatname))));
0503: enterInner(c);
0504: }
0505: } else if (value instanceof NameAndType) {
0506: NameAndType nt = (NameAndType) value;
0507: poolbuf.appendByte(CONSTANT_NameandType);
0508: poolbuf.appendChar(pool.put(nt.name));
0509: poolbuf.appendChar(pool.put(typeSig(nt.type)));
0510: } else if (value instanceof Integer) {
0511: poolbuf.appendByte(CONSTANT_Integer);
0512: poolbuf.appendInt(((Integer) value).intValue());
0513: } else if (value instanceof Long) {
0514: poolbuf.appendByte(CONSTANT_Long);
0515: poolbuf.appendLong(((Long) value).longValue());
0516: i++;
0517: } else if (value instanceof Float) {
0518: poolbuf.appendByte(CONSTANT_Float);
0519: poolbuf.appendFloat(((Float) value).floatValue());
0520: } else if (value instanceof Double) {
0521: poolbuf.appendByte(CONSTANT_Double);
0522: poolbuf.appendDouble(((Double) value).doubleValue());
0523: i++;
0524: } else if (value instanceof String) {
0525: poolbuf.appendByte(CONSTANT_String);
0526: poolbuf.appendChar(pool.put(names
0527: .fromString((String) value)));
0528: } else if (value instanceof Type) {
0529: Type type = (Type) value;
0530: if (type.tag == CLASS)
0531: enterInner((ClassSymbol) type.tsym);
0532: poolbuf.appendByte(CONSTANT_Class);
0533: poolbuf.appendChar(pool.put(xClassName(type)));
0534: } else {
0535: assert false : "writePool " + value;
0536: }
0537: i++;
0538: }
0539: if (pool.pp > Pool.MAX_ENTRIES)
0540: throw new PoolOverflow();
0541: putChar(poolbuf, poolCountIdx, pool.pp);
0542: }
0543:
0544: /** Given a field, return its name.
0545: */
0546: Name fieldName(Symbol sym) {
0547: if (scramble && (sym.flags() & PRIVATE) != 0 || scrambleAll
0548: && (sym.flags() & (PROTECTED | PUBLIC)) == 0)
0549: return names.fromString("_$" + sym.name.index);
0550: else
0551: return sym.name;
0552: }
0553:
0554: /** Given a symbol, return its name-and-type.
0555: */
0556: NameAndType nameType(Symbol sym) {
0557: return new NameAndType(fieldName(sym), retrofit ? sym
0558: .erasure(types) : sym.externalType(types));
0559: // if we retrofit, then the NameAndType has been read in as is
0560: // and no change is necessary. If we compile normally, the
0561: // NameAndType is generated from a symbol reference, and the
0562: // adjustment of adding an additional this$n parameter needs to be made.
0563: }
0564:
0565: /******************************************************************
0566: * Writing Attributes
0567: ******************************************************************/
0568:
0569: /** Write header for an attribute to data buffer and return
0570: * position past attribute length index.
0571: */
0572: int writeAttr(Name attrName) {
0573: databuf.appendChar(pool.put(attrName));
0574: databuf.appendInt(0);
0575: return databuf.length;
0576: }
0577:
0578: /** Fill in attribute length.
0579: */
0580: void endAttr(int index) {
0581: putInt(databuf, index - 4, databuf.length - index);
0582: }
0583:
0584: /** Leave space for attribute count and return index for
0585: * number of attributes field.
0586: */
0587: int beginAttrs() {
0588: databuf.appendChar(0);
0589: return databuf.length;
0590: }
0591:
0592: /** Fill in number of attributes.
0593: */
0594: void endAttrs(int index, int count) {
0595: putChar(databuf, index - 2, count);
0596: }
0597:
0598: /** Write the EnclosingMethod attribute if needed.
0599: * Returns the number of attributes written (0 or 1).
0600: */
0601: int writeEnclosingMethodAttribute(ClassSymbol c) {
0602: if (!target.hasEnclosingMethodAttribute()
0603: || c.owner.kind != MTH && // neither a local class
0604: c.name != names.empty) // nor anonymous
0605: return 0;
0606:
0607: int alenIdx = writeAttr(names.EnclosingMethod);
0608: ClassSymbol enclClass = c.owner.enclClass();
0609: MethodSymbol enclMethod = (c.owner.type == null // local to init block
0610: || c.owner.kind != MTH) // or member init
0611: ? null
0612: : (MethodSymbol) c.owner;
0613: databuf.appendChar(pool.put(enclClass));
0614: databuf.appendChar(enclMethod == null ? 0 : pool
0615: .put(nameType(c.owner)));
0616: endAttr(alenIdx);
0617: return 1;
0618: }
0619:
0620: /** Write flag attributes; return number of attributes written.
0621: */
0622: int writeFlagAttrs(long flags) {
0623: int acount = 0;
0624: if ((flags & DEPRECATED) != 0) {
0625: int alenIdx = writeAttr(names.Deprecated);
0626: endAttr(alenIdx);
0627: acount++;
0628: }
0629: if ((flags & ENUM) != 0 && !target.useEnumFlag()) {
0630: int alenIdx = writeAttr(names.Enum);
0631: endAttr(alenIdx);
0632: acount++;
0633: }
0634: if ((flags & SYNTHETIC) != 0 && !target.useSyntheticFlag()) {
0635: int alenIdx = writeAttr(names.Synthetic);
0636: endAttr(alenIdx);
0637: acount++;
0638: }
0639: if ((flags & BRIDGE) != 0 && !target.useBridgeFlag()) {
0640: int alenIdx = writeAttr(names.Bridge);
0641: endAttr(alenIdx);
0642: acount++;
0643: }
0644: if ((flags & VARARGS) != 0 && !target.useVarargsFlag()) {
0645: int alenIdx = writeAttr(names.Varargs);
0646: endAttr(alenIdx);
0647: acount++;
0648: }
0649: if ((flags & ANNOTATION) != 0 && !target.useAnnotationFlag()) {
0650: int alenIdx = writeAttr(names.Annotation);
0651: endAttr(alenIdx);
0652: acount++;
0653: }
0654: return acount;
0655: }
0656:
0657: /** Write member (field or method) attributes;
0658: * return number of attributes written.
0659: */
0660: int writeMemberAttrs(Symbol sym) {
0661: int acount = writeFlagAttrs(sym.flags());
0662: long flags = sym.flags();
0663: if (source.allowGenerics()
0664: && (flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC
0665: && (flags & ANONCONSTR) == 0
0666: && (!types.isSameType(sym.type, sym.erasure(types)) || hasTypeVar(sym.type
0667: .getThrownTypes()))) {
0668: // note that a local class with captured variables
0669: // will get a signature attribute
0670: int alenIdx = writeAttr(names.Signature);
0671: databuf.appendChar(pool.put(typeSig(sym.type)));
0672: endAttr(alenIdx);
0673: acount++;
0674: }
0675: acount += writeJavaAnnotations(sym.getAnnotationMirrors());
0676: return acount;
0677: }
0678:
0679: /** Write method parameter annotations;
0680: * return number of attributes written.
0681: */
0682: int writeParameterAttrs(MethodSymbol m) {
0683: boolean hasVisible = false;
0684: boolean hasInvisible = false;
0685: if (m.params != null)
0686: for (VarSymbol s : m.params) {
0687: for (Attribute.Compound a : s.getAnnotationMirrors()) {
0688: switch (getRetention(a.type.tsym)) {
0689: case SOURCE:
0690: break;
0691: case CLASS:
0692: hasInvisible = true;
0693: break;
0694: case RUNTIME:
0695: hasVisible = true;
0696: break;
0697: default:
0698: ;// /* fail soft */ throw new AssertionError(vis);
0699: }
0700: }
0701: }
0702:
0703: int attrCount = 0;
0704: if (hasVisible) {
0705: int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
0706: databuf.appendByte(m.params.length());
0707: for (VarSymbol s : m.params) {
0708: ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
0709: for (Attribute.Compound a : s.getAnnotationMirrors())
0710: if (getRetention(a.type.tsym) == RetentionPolicy.RUNTIME)
0711: buf.append(a);
0712: databuf.appendChar(buf.length());
0713: for (Attribute.Compound a : buf)
0714: writeCompoundAttribute(a);
0715: }
0716: endAttr(attrIndex);
0717: attrCount++;
0718: }
0719: if (hasInvisible) {
0720: int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
0721: databuf.appendByte(m.params.length());
0722: for (VarSymbol s : m.params) {
0723: ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
0724: for (Attribute.Compound a : s.getAnnotationMirrors())
0725: if (getRetention(a.type.tsym) == RetentionPolicy.CLASS)
0726: buf.append(a);
0727: databuf.appendChar(buf.length());
0728: for (Attribute.Compound a : buf)
0729: writeCompoundAttribute(a);
0730: }
0731: endAttr(attrIndex);
0732: attrCount++;
0733: }
0734: return attrCount;
0735: }
0736:
0737: /**********************************************************************
0738: * Writing Java-language annotations (aka metadata, attributes)
0739: **********************************************************************/
0740:
0741: /** Write Java-language annotations; return number of JVM
0742: * attributes written (zero or one).
0743: */
0744: int writeJavaAnnotations(List<Attribute.Compound> attrs) {
0745: if (attrs.isEmpty())
0746: return 0;
0747: ListBuffer<Attribute.Compound> visibles = new ListBuffer<Attribute.Compound>();
0748: ListBuffer<Attribute.Compound> invisibles = new ListBuffer<Attribute.Compound>();
0749: for (Attribute.Compound a : attrs) {
0750: switch (getRetention(a.type.tsym)) {
0751: case SOURCE:
0752: break;
0753: case CLASS:
0754: invisibles.append(a);
0755: break;
0756: case RUNTIME:
0757: visibles.append(a);
0758: break;
0759: default:
0760: ;// /* fail soft */ throw new AssertionError(vis);
0761: }
0762: }
0763:
0764: int attrCount = 0;
0765: if (visibles.length() != 0) {
0766: int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
0767: databuf.appendChar(visibles.length());
0768: for (Attribute.Compound a : visibles)
0769: writeCompoundAttribute(a);
0770: endAttr(attrIndex);
0771: attrCount++;
0772: }
0773: if (invisibles.length() != 0) {
0774: int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
0775: databuf.appendChar(invisibles.length());
0776: for (Attribute.Compound a : invisibles)
0777: writeCompoundAttribute(a);
0778: endAttr(attrIndex);
0779: attrCount++;
0780: }
0781: return attrCount;
0782: }
0783:
0784: /** A mirror of java.lang.annotation.RetentionPolicy. */
0785: enum RetentionPolicy {
0786: SOURCE, CLASS, RUNTIME
0787: }
0788:
0789: RetentionPolicy getRetention(TypeSymbol annotationType) {
0790: RetentionPolicy vis = RetentionPolicy.CLASS; // the default
0791: Attribute.Compound c = annotationType
0792: .attribute(syms.retentionType.tsym);
0793: if (c != null) {
0794: Attribute value = c.member(names.value);
0795: if (value != null && value instanceof Attribute.Enum) {
0796: Name levelName = ((Attribute.Enum) value).value.name;
0797: if (levelName == names.SOURCE)
0798: vis = RetentionPolicy.SOURCE;
0799: else if (levelName == names.CLASS)
0800: vis = RetentionPolicy.CLASS;
0801: else if (levelName == names.RUNTIME)
0802: vis = RetentionPolicy.RUNTIME;
0803: else
0804: ;// /* fail soft */ throw new AssertionError(levelName);
0805: }
0806: }
0807: return vis;
0808: }
0809:
0810: /** A visitor to write an attribute including its leading
0811: * single-character marker.
0812: */
0813: class AttributeWriter implements Attribute.Visitor {
0814: public void visitConstant(Attribute.Constant _value) {
0815: Object value = _value.value;
0816: switch (_value.type.tag) {
0817: case BYTE:
0818: databuf.appendByte('B');
0819: break;
0820: case CHAR:
0821: databuf.appendByte('C');
0822: break;
0823: case SHORT:
0824: databuf.appendByte('S');
0825: break;
0826: case INT:
0827: databuf.appendByte('I');
0828: break;
0829: case LONG:
0830: databuf.appendByte('J');
0831: break;
0832: case FLOAT:
0833: databuf.appendByte('F');
0834: break;
0835: case DOUBLE:
0836: databuf.appendByte('D');
0837: break;
0838: case BOOLEAN:
0839: databuf.appendByte('Z');
0840: break;
0841: case CLASS:
0842: assert value instanceof String;
0843: databuf.appendByte('s');
0844: value = names.fromString(value.toString()); // CONSTANT_Utf8
0845: break;
0846: default:
0847: throw new AssertionError(_value.type);
0848: }
0849: databuf.appendChar(pool.put(value));
0850: }
0851:
0852: public void visitEnum(Attribute.Enum e) {
0853: databuf.appendByte('e');
0854: databuf.appendChar(pool.put(typeSig(e.value.type)));
0855: databuf.appendChar(pool.put(e.value.name));
0856: }
0857:
0858: public void visitClass(Attribute.Class clazz) {
0859: databuf.appendByte('c');
0860: databuf.appendChar(pool.put(typeSig(clazz.type)));
0861: }
0862:
0863: public void visitCompound(Attribute.Compound compound) {
0864: databuf.appendByte('@');
0865: writeCompoundAttribute(compound);
0866: }
0867:
0868: public void visitError(Attribute.Error x) {
0869: throw new AssertionError(x);
0870: }
0871:
0872: public void visitArray(Attribute.Array array) {
0873: databuf.appendByte('[');
0874: databuf.appendChar(array.values.length);
0875: for (Attribute a : array.values) {
0876: a.accept(this );
0877: }
0878: }
0879: }
0880:
0881: AttributeWriter awriter = new AttributeWriter();
0882:
0883: /** Write a compound attribute excluding the '@' marker. */
0884: void writeCompoundAttribute(Attribute.Compound c) {
0885: databuf.appendChar(pool.put(typeSig(c.type)));
0886: databuf.appendChar(c.values.length());
0887: for (Pair<Symbol.MethodSymbol, Attribute> p : c.values) {
0888: databuf.appendChar(pool.put(p.fst.name));
0889: p.snd.accept(awriter);
0890: }
0891: }
0892:
0893: /**********************************************************************
0894: * Writing Objects
0895: **********************************************************************/
0896:
0897: /** Enter an inner class into the `innerClasses' set/queue.
0898: */
0899: void enterInner(ClassSymbol c) {
0900: assert !c.type.isCompound();
0901: try {
0902: c.complete();
0903: } catch (CompletionFailure ex) {
0904: System.err.println("error: " + c + ": " + ex.getMessage());
0905: throw ex;
0906: }
0907: if (c.type.tag != CLASS)
0908: return; // arrays
0909: if (pool != null
0910: && // pool might be null if called from xClassName
0911: c.owner.kind != PCK
0912: && (innerClasses == null || !innerClasses.contains(c))) {
0913: // log.errWriter.println("enter inner " + c);//DEBUG
0914: if (c.owner.kind == TYP)
0915: enterInner((ClassSymbol) c.owner);
0916: pool.put(c);
0917: pool.put(c.name);
0918: if (innerClasses == null) {
0919: innerClasses = new HashSet<ClassSymbol>();
0920: innerClassesQueue = new ListBuffer<ClassSymbol>();
0921: pool.put(names.InnerClasses);
0922: }
0923: innerClasses.add(c);
0924: innerClassesQueue.append(c);
0925: }
0926: }
0927:
0928: /** Write "inner classes" attribute.
0929: */
0930: void writeInnerClasses() {
0931: int alenIdx = writeAttr(names.InnerClasses);
0932: databuf.appendChar(innerClassesQueue.length());
0933: for (List<ClassSymbol> l = innerClassesQueue.toList(); l
0934: .nonEmpty(); l = l.tail) {
0935: ClassSymbol inner = l.head;
0936: char flags = (char) adjustFlags(inner.flags_field);
0937: if ((flags & INTERFACE) != 0)
0938: flags |= ABSTRACT; // Interfaces are always ABSTRACT
0939: if (inner.name.isEmpty())
0940: flags &= ~FINAL; // Anonymous class: unset FINAL flag
0941: if (dumpInnerClassModifiers) {
0942: log.errWriter.println("INNERCLASS " + inner.name);
0943: log.errWriter.println("---" + flagNames(flags));
0944: }
0945: databuf.appendChar(pool.get(inner));
0946: databuf.appendChar(inner.owner.kind == TYP ? pool
0947: .get(inner.owner) : 0);
0948: databuf.appendChar(inner.name.len != 0 ? pool
0949: .get(inner.name) : 0);
0950: databuf.appendChar(flags);
0951: }
0952: endAttr(alenIdx);
0953: }
0954:
0955: /** Write field symbol, entering all references into constant pool.
0956: */
0957: void writeField(VarSymbol v) {
0958: int flags = adjustFlags(v.flags());
0959: databuf.appendChar(flags);
0960: if (dumpFieldModifiers) {
0961: log.errWriter.println("FIELD " + fieldName(v));
0962: log.errWriter.println("---" + flagNames(v.flags()));
0963: }
0964: databuf.appendChar(pool.put(fieldName(v)));
0965: databuf.appendChar(pool.put(typeSig(v.erasure(types))));
0966: int acountIdx = beginAttrs();
0967: int acount = 0;
0968: if (v.getConstValue() != null) {
0969: int alenIdx = writeAttr(names.ConstantValue);
0970: databuf.appendChar(pool.put(v.getConstValue()));
0971: endAttr(alenIdx);
0972: acount++;
0973: }
0974: acount += writeMemberAttrs(v);
0975: endAttrs(acountIdx, acount);
0976: }
0977:
0978: /** Write method symbol, entering all references into constant pool.
0979: */
0980: void writeMethod(MethodSymbol m) {
0981: int flags = adjustFlags(m.flags());
0982: databuf.appendChar(flags);
0983: if (dumpMethodModifiers) {
0984: log.errWriter.println("METHOD " + fieldName(m));
0985: log.errWriter.println("---" + flagNames(m.flags()));
0986: }
0987: databuf.appendChar(pool.put(fieldName(m)));
0988: databuf.appendChar(pool.put(typeSig(m.externalType(types))));
0989: int acountIdx = beginAttrs();
0990: int acount = 0;
0991: if (m.code != null) {
0992: int alenIdx = writeAttr(names.Code);
0993: writeCode(m.code);
0994: m.code = null; // to conserve space
0995: endAttr(alenIdx);
0996: acount++;
0997: }
0998: List<Type> thrown = m.erasure(types).getThrownTypes();
0999: if (thrown.nonEmpty()) {
1000: int alenIdx = writeAttr(names.Exceptions);
1001: databuf.appendChar(thrown.length());
1002: for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1003: databuf.appendChar(pool.put(l.head.tsym));
1004: endAttr(alenIdx);
1005: acount++;
1006: }
1007: if (m.defaultValue != null) {
1008: int alenIdx = writeAttr(names.AnnotationDefault);
1009: m.defaultValue.accept(awriter);
1010: endAttr(alenIdx);
1011: acount++;
1012: }
1013: acount += writeMemberAttrs(m);
1014: acount += writeParameterAttrs(m);
1015: endAttrs(acountIdx, acount);
1016: }
1017:
1018: /** Write code attribute of method.
1019: */
1020: void writeCode(Code code) {
1021: databuf.appendChar(code.max_stack);
1022: databuf.appendChar(code.max_locals);
1023: databuf.appendInt(code.cp);
1024: databuf.appendBytes(code.code, 0, code.cp);
1025: databuf.appendChar(code.catchInfo.length());
1026: for (List<char[]> l = code.catchInfo.toList(); l.nonEmpty(); l = l.tail) {
1027: for (int i = 0; i < l.head.length; i++)
1028: databuf.appendChar(l.head[i]);
1029: }
1030: int acountIdx = beginAttrs();
1031: int acount = 0;
1032:
1033: if (code.lineInfo.nonEmpty()) {
1034: int alenIdx = writeAttr(names.LineNumberTable);
1035: databuf.appendChar(code.lineInfo.length());
1036: for (List<char[]> l = code.lineInfo.reverse(); l.nonEmpty(); l = l.tail)
1037: for (int i = 0; i < l.head.length; i++)
1038: databuf.appendChar(l.head[i]);
1039: endAttr(alenIdx);
1040: acount++;
1041: }
1042:
1043: if (genCrt && (code.crt != null)) {
1044: CRTable crt = code.crt;
1045: int alenIdx = writeAttr(names.CharacterRangeTable);
1046: int crtIdx = beginAttrs();
1047: int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1048: endAttrs(crtIdx, crtEntries);
1049: endAttr(alenIdx);
1050: acount++;
1051: }
1052:
1053: // counter for number of generic local variables
1054: int nGenericVars = 0;
1055:
1056: if (code.varBufferSize > 0) {
1057: int alenIdx = writeAttr(names.LocalVariableTable);
1058: databuf.appendChar(code.varBufferSize);
1059:
1060: for (int i = 0; i < code.varBufferSize; i++) {
1061: Code.LocalVar var = code.varBuffer[i];
1062:
1063: // write variable info
1064: assert var.start_pc >= 0;
1065: assert var.start_pc <= code.cp;
1066: databuf.appendChar(var.start_pc);
1067: assert var.length >= 0;
1068: assert (var.start_pc + var.length) <= code.cp;
1069: databuf.appendChar(var.length);
1070: VarSymbol sym = var.sym;
1071: databuf.appendChar(pool.put(sym.name));
1072: Type vartype = sym.erasure(types);
1073: if (!types.isSameType(sym.type, vartype))
1074: nGenericVars++;
1075: databuf.appendChar(pool.put(typeSig(vartype)));
1076: databuf.appendChar(var.reg);
1077: }
1078: endAttr(alenIdx);
1079: acount++;
1080: }
1081:
1082: if (nGenericVars > 0) {
1083: int alenIdx = writeAttr(names.LocalVariableTypeTable);
1084: databuf.appendChar(nGenericVars);
1085: int count = 0;
1086:
1087: for (int i = 0; i < code.varBufferSize; i++) {
1088: Code.LocalVar var = code.varBuffer[i];
1089: VarSymbol sym = var.sym;
1090: if (types.isSameType(sym.type, sym.erasure(types)))
1091: continue;
1092: count++;
1093: // write variable info
1094: databuf.appendChar(var.start_pc);
1095: databuf.appendChar(var.length);
1096: databuf.appendChar(pool.put(sym.name));
1097: databuf.appendChar(pool.put(typeSig(sym.type)));
1098: databuf.appendChar(var.reg);
1099: }
1100: assert count == nGenericVars;
1101: endAttr(alenIdx);
1102: acount++;
1103: }
1104:
1105: if (code.stackMapBufferSize > 0) {
1106: if (debugstackmap)
1107: System.out.println("Stack map for " + code.meth);
1108: int alenIdx = writeAttr(code.stackMap
1109: .getAttributeName(names));
1110: writeStackMap(code);
1111: endAttr(alenIdx);
1112: acount++;
1113: }
1114: endAttrs(acountIdx, acount);
1115: }
1116:
1117: void writeStackMap(Code code) {
1118: int nframes = code.stackMapBufferSize;
1119: if (debugstackmap)
1120: System.out.println(" nframes = " + nframes);
1121: databuf.appendChar(nframes);
1122:
1123: switch (code.stackMap) {
1124: case CLDC:
1125: for (int i = 0; i < nframes; i++) {
1126: if (debugstackmap)
1127: System.out.print(" " + i + ":");
1128: Code.StackMapFrame frame = code.stackMapBuffer[i];
1129:
1130: // output PC
1131: if (debugstackmap)
1132: System.out.print(" pc=" + frame.pc);
1133: databuf.appendChar(frame.pc);
1134:
1135: // output locals
1136: int localCount = 0;
1137: for (int j = 0; j < frame.locals.length; j += (target
1138: .generateEmptyAfterBig() ? 1 : Code
1139: .width(frame.locals[j]))) {
1140: localCount++;
1141: }
1142: if (debugstackmap)
1143: System.out.print(" nlocals=" + localCount);
1144: databuf.appendChar(localCount);
1145: for (int j = 0; j < frame.locals.length; j += (target
1146: .generateEmptyAfterBig() ? 1 : Code
1147: .width(frame.locals[j]))) {
1148: if (debugstackmap)
1149: System.out.print(" local[" + j + "]=");
1150: writeStackMapType(frame.locals[j]);
1151: }
1152:
1153: // output stack
1154: int stackCount = 0;
1155: for (int j = 0; j < frame.stack.length; j += (target
1156: .generateEmptyAfterBig() ? 1 : Code
1157: .width(frame.stack[j]))) {
1158: stackCount++;
1159: }
1160: if (debugstackmap)
1161: System.out.print(" nstack=" + stackCount);
1162: databuf.appendChar(stackCount);
1163: for (int j = 0; j < frame.stack.length; j += (target
1164: .generateEmptyAfterBig() ? 1 : Code
1165: .width(frame.stack[j]))) {
1166: if (debugstackmap)
1167: System.out.print(" stack[" + j + "]=");
1168: writeStackMapType(frame.stack[j]);
1169: }
1170: if (debugstackmap)
1171: System.out.println();
1172: }
1173: break;
1174: case JSR202: {
1175: assert code.stackMapBuffer == null;
1176: for (int i = 0; i < nframes; i++) {
1177: if (debugstackmap)
1178: System.out.print(" " + i + ":");
1179: StackMapTableFrame frame = code.stackMapTableBuffer[i];
1180: frame.write(this );
1181: if (debugstackmap)
1182: System.out.println();
1183: }
1184: break;
1185: }
1186: default:
1187: throw new AssertionError("Unexpected stackmap format value");
1188: }
1189: }
1190:
1191: //where
1192: void writeStackMapType(Type t) {
1193: if (t == null) {
1194: if (debugstackmap)
1195: System.out.print("empty");
1196: databuf.appendByte(0);
1197: } else
1198: switch (t.tag) {
1199: case BYTE:
1200: case CHAR:
1201: case SHORT:
1202: case INT:
1203: case BOOLEAN:
1204: if (debugstackmap)
1205: System.out.print("int");
1206: databuf.appendByte(1);
1207: break;
1208: case FLOAT:
1209: if (debugstackmap)
1210: System.out.print("float");
1211: databuf.appendByte(2);
1212: break;
1213: case DOUBLE:
1214: if (debugstackmap)
1215: System.out.print("double");
1216: databuf.appendByte(3);
1217: break;
1218: case LONG:
1219: if (debugstackmap)
1220: System.out.print("long");
1221: databuf.appendByte(4);
1222: break;
1223: case BOT: // null
1224: if (debugstackmap)
1225: System.out.print("null");
1226: databuf.appendByte(5);
1227: break;
1228: case CLASS:
1229: case ARRAY:
1230: if (debugstackmap)
1231: System.out.print("object(" + t + ")");
1232: databuf.appendByte(7);
1233: databuf.appendChar(pool.put(t));
1234: break;
1235: case TYPEVAR:
1236: if (debugstackmap)
1237: System.out.print("object(" + types.erasure(t).tsym
1238: + ")");
1239: databuf.appendByte(7);
1240: databuf.appendChar(pool.put(types.erasure(t).tsym));
1241: break;
1242: case UNINITIALIZED_THIS:
1243: if (debugstackmap)
1244: System.out.print("uninit_this");
1245: databuf.appendByte(6);
1246: break;
1247: case UNINITIALIZED_OBJECT: {
1248: UninitializedType uninitType = (UninitializedType) t;
1249: databuf.appendByte(8);
1250: if (debugstackmap)
1251: System.out.print("uninit_object@"
1252: + uninitType.offset);
1253: databuf.appendChar(uninitType.offset);
1254: }
1255: break;
1256: default:
1257: throw new AssertionError();
1258: }
1259: }
1260:
1261: /** An entry in the JSR202 StackMapTable */
1262: abstract static class StackMapTableFrame {
1263: abstract int getFrameType();
1264:
1265: void write(ClassWriter writer) {
1266: int frameType = getFrameType();
1267: writer.databuf.appendByte(frameType);
1268: if (writer.debugstackmap)
1269: System.out.print(" frame_type=" + frameType);
1270: }
1271:
1272: static class SameFrame extends StackMapTableFrame {
1273: final int offsetDelta;
1274:
1275: SameFrame(int offsetDelta) {
1276: this .offsetDelta = offsetDelta;
1277: }
1278:
1279: int getFrameType() {
1280: return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta
1281: : SAME_FRAME_EXTENDED;
1282: }
1283:
1284: @Override
1285: void write(ClassWriter writer) {
1286: super .write(writer);
1287: if (getFrameType() == SAME_FRAME_EXTENDED) {
1288: writer.databuf.appendChar(offsetDelta);
1289: if (writer.debugstackmap) {
1290: System.out
1291: .print(" offset_delta=" + offsetDelta);
1292: }
1293: }
1294: }
1295: }
1296:
1297: static class SameLocals1StackItemFrame extends
1298: StackMapTableFrame {
1299: final int offsetDelta;
1300: final Type stack;
1301:
1302: SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1303: this .offsetDelta = offsetDelta;
1304: this .stack = stack;
1305: }
1306:
1307: int getFrameType() {
1308: return (offsetDelta < SAME_FRAME_SIZE) ? (SAME_FRAME_SIZE + offsetDelta)
1309: : SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1310: }
1311:
1312: @Override
1313: void write(ClassWriter writer) {
1314: super .write(writer);
1315: if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1316: writer.databuf.appendChar(offsetDelta);
1317: if (writer.debugstackmap) {
1318: System.out
1319: .print(" offset_delta=" + offsetDelta);
1320: }
1321: }
1322: if (writer.debugstackmap) {
1323: System.out.print(" stack[" + 0 + "]=");
1324: }
1325: writer.writeStackMapType(stack);
1326: }
1327: }
1328:
1329: static class ChopFrame extends StackMapTableFrame {
1330: final int frameType;
1331: final int offsetDelta;
1332:
1333: ChopFrame(int frameType, int offsetDelta) {
1334: this .frameType = frameType;
1335: this .offsetDelta = offsetDelta;
1336: }
1337:
1338: int getFrameType() {
1339: return frameType;
1340: }
1341:
1342: @Override
1343: void write(ClassWriter writer) {
1344: super .write(writer);
1345: writer.databuf.appendChar(offsetDelta);
1346: if (writer.debugstackmap) {
1347: System.out.print(" offset_delta=" + offsetDelta);
1348: }
1349: }
1350: }
1351:
1352: static class AppendFrame extends StackMapTableFrame {
1353: final int frameType;
1354: final int offsetDelta;
1355: final Type[] locals;
1356:
1357: AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1358: this .frameType = frameType;
1359: this .offsetDelta = offsetDelta;
1360: this .locals = locals;
1361: }
1362:
1363: int getFrameType() {
1364: return frameType;
1365: }
1366:
1367: @Override
1368: void write(ClassWriter writer) {
1369: super .write(writer);
1370: writer.databuf.appendChar(offsetDelta);
1371: if (writer.debugstackmap) {
1372: System.out.print(" offset_delta=" + offsetDelta);
1373: }
1374: for (int i = 0; i < locals.length; i++) {
1375: if (writer.debugstackmap)
1376: System.out.print(" locals[" + i + "]=");
1377: writer.writeStackMapType(locals[i]);
1378: }
1379: }
1380: }
1381:
1382: static class FullFrame extends StackMapTableFrame {
1383: final int offsetDelta;
1384: final Type[] locals;
1385: final Type[] stack;
1386:
1387: FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1388: this .offsetDelta = offsetDelta;
1389: this .locals = locals;
1390: this .stack = stack;
1391: }
1392:
1393: int getFrameType() {
1394: return FULL_FRAME;
1395: }
1396:
1397: @Override
1398: void write(ClassWriter writer) {
1399: super .write(writer);
1400: writer.databuf.appendChar(offsetDelta);
1401: writer.databuf.appendChar(locals.length);
1402: if (writer.debugstackmap) {
1403: System.out.print(" offset_delta=" + offsetDelta);
1404: System.out.print(" nlocals=" + locals.length);
1405: }
1406: for (int i = 0; i < locals.length; i++) {
1407: if (writer.debugstackmap)
1408: System.out.print(" locals[" + i + "]=");
1409: writer.writeStackMapType(locals[i]);
1410: }
1411:
1412: writer.databuf.appendChar(stack.length);
1413: if (writer.debugstackmap) {
1414: System.out.print(" nstack=" + stack.length);
1415: }
1416: for (int i = 0; i < stack.length; i++) {
1417: if (writer.debugstackmap)
1418: System.out.print(" stack[" + i + "]=");
1419: writer.writeStackMapType(stack[i]);
1420: }
1421: }
1422: }
1423:
1424: /** Compare this frame with the previous frame and produce
1425: * an entry of compressed stack map frame. */
1426: static StackMapTableFrame getInstance(
1427: Code.StackMapFrame this _frame, int prev_pc,
1428: Type[] prev_locals, Types types) {
1429: Type[] locals = this _frame.locals;
1430: Type[] stack = this _frame.stack;
1431: int offset_delta = this _frame.pc - prev_pc - 1;
1432: if (stack.length == 1) {
1433: if (locals.length == prev_locals.length
1434: && compare(prev_locals, locals, types) == 0) {
1435: return new SameLocals1StackItemFrame(offset_delta,
1436: stack[0]);
1437: }
1438: } else if (stack.length == 0) {
1439: int diff_length = compare(prev_locals, locals, types);
1440: if (diff_length == 0) {
1441: return new SameFrame(offset_delta);
1442: } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length
1443: && diff_length < 0) {
1444: // APPEND
1445: Type[] local_diff = new Type[-diff_length];
1446: for (int i = prev_locals.length, j = 0; i < locals.length; i++, j++) {
1447: local_diff[j] = locals[i];
1448: }
1449: return new AppendFrame(SAME_FRAME_EXTENDED
1450: - diff_length, offset_delta, local_diff);
1451: } else if (0 < diff_length
1452: && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1453: // CHOP
1454: return new ChopFrame(SAME_FRAME_EXTENDED
1455: - diff_length, offset_delta);
1456: }
1457: }
1458: // FULL_FRAME
1459: return new FullFrame(offset_delta, locals, stack);
1460: }
1461:
1462: static boolean isInt(Type t) {
1463: return (t.tag < TypeTags.INT || t.tag == TypeTags.BOOLEAN);
1464: }
1465:
1466: static boolean isSameType(Type t1, Type t2, Types types) {
1467: if (t1 == null) {
1468: return t2 == null;
1469: }
1470: if (t2 == null) {
1471: return false;
1472: }
1473:
1474: if (isInt(t1) && isInt(t2)) {
1475: return true;
1476: }
1477:
1478: if (t1.tag == UNINITIALIZED_THIS) {
1479: return t2.tag == UNINITIALIZED_THIS;
1480: } else if (t1.tag == UNINITIALIZED_OBJECT) {
1481: if (t2.tag == UNINITIALIZED_OBJECT) {
1482: return ((UninitializedType) t1).offset == ((UninitializedType) t2).offset;
1483: } else {
1484: return false;
1485: }
1486: } else if (t2.tag == UNINITIALIZED_THIS
1487: || t2.tag == UNINITIALIZED_OBJECT) {
1488: return false;
1489: }
1490:
1491: return types.isSameType(t1, t2);
1492: }
1493:
1494: static int compare(Type[] arr1, Type[] arr2, Types types) {
1495: int diff_length = arr1.length - arr2.length;
1496: if (diff_length > MAX_LOCAL_LENGTH_DIFF
1497: || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1498: return Integer.MAX_VALUE;
1499: }
1500: int len = (diff_length > 0) ? arr2.length : arr1.length;
1501: for (int i = 0; i < len; i++) {
1502: if (!isSameType(arr1[i], arr2[i], types)) {
1503: return Integer.MAX_VALUE;
1504: }
1505: }
1506: return diff_length;
1507: }
1508: }
1509:
1510: void writeFields(Scope.Entry e) {
1511: // process them in reverse sibling order;
1512: // i.e., process them in declaration order.
1513: List<VarSymbol> vars = List.nil();
1514: for (Scope.Entry i = e; i != null; i = i.sibling) {
1515: if (i.sym.kind == VAR)
1516: vars = vars.prepend((VarSymbol) i.sym);
1517: }
1518: while (vars.nonEmpty()) {
1519: writeField(vars.head);
1520: vars = vars.tail;
1521: }
1522: }
1523:
1524: void writeMethods(Scope.Entry e) {
1525: List<MethodSymbol> methods = List.nil();
1526: for (Scope.Entry i = e; i != null; i = i.sibling) {
1527: if (i.sym.kind == MTH
1528: && (i.sym.flags() & HYPOTHETICAL) == 0)
1529: methods = methods.prepend((MethodSymbol) i.sym);
1530: }
1531: while (methods.nonEmpty()) {
1532: writeMethod(methods.head);
1533: methods = methods.tail;
1534: }
1535: }
1536:
1537: /** Emit a class file for a given class.
1538: * @param c The class from which a class file is generated.
1539: */
1540: public JavaFileObject writeClass(ClassSymbol c) throws IOException,
1541: PoolOverflow, StringOverflow {
1542: JavaFileObject outFile = fileManager.getJavaFileForOutput(
1543: CLASS_OUTPUT, c.flatname.toString(),
1544: JavaFileObject.Kind.CLASS, c.sourcefile);
1545: OutputStream out = outFile.openOutputStream();
1546: try {
1547: writeClassFile(out, c);
1548: if (verbose)
1549: log.errWriter.println(log.getLocalizedString(
1550: "verbose.wrote.file", outFile));
1551: out.close();
1552: out = null;
1553: } finally {
1554: if (out != null) {
1555: // if we are propogating an exception, delete the file
1556: out.close();
1557: outFile.delete();
1558: outFile = null;
1559: }
1560: }
1561: return outFile; // may be null if write failed
1562: }
1563:
1564: /** Write class `c' to outstream `out'.
1565: */
1566: public void writeClassFile(OutputStream out, ClassSymbol c)
1567: throws IOException, PoolOverflow, StringOverflow {
1568: assert (c.flags() & COMPOUND) == 0;
1569: databuf.reset();
1570: poolbuf.reset();
1571: sigbuf.reset();
1572: pool = c.pool;
1573: innerClasses = null;
1574: innerClassesQueue = null;
1575:
1576: Type super type = types.super type(c.type);
1577: List<Type> interfaces = types.interfaces(c.type);
1578: List<Type> typarams = c.type.getTypeArguments();
1579:
1580: int flags = adjustFlags(c.flags());
1581: if ((flags & PROTECTED) != 0)
1582: flags |= PUBLIC;
1583: flags = flags & ClassFlags & ~STRICTFP;
1584: if ((flags & INTERFACE) == 0)
1585: flags |= ACC_SUPER;
1586: if (c.isInner() && c.name.isEmpty())
1587: flags &= ~FINAL;
1588: if (dumpClassModifiers) {
1589: log.errWriter.println();
1590: log.errWriter.println("CLASSFILE " + c.getQualifiedName());
1591: log.errWriter.println("---" + flagNames(flags));
1592: }
1593: databuf.appendChar(flags);
1594:
1595: databuf.appendChar(pool.put(c));
1596: databuf.appendChar(super type.tag == CLASS ? pool
1597: .put(super type.tsym) : 0);
1598: databuf.appendChar(interfaces.length());
1599: for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1600: databuf.appendChar(pool.put(l.head.tsym));
1601: int fieldsCount = 0;
1602: int methodsCount = 0;
1603: for (Scope.Entry e = c.members().elems; e != null; e = e.sibling) {
1604: switch (e.sym.kind) {
1605: case VAR:
1606: fieldsCount++;
1607: break;
1608: case MTH:
1609: if ((e.sym.flags() & HYPOTHETICAL) == 0)
1610: methodsCount++;
1611: break;
1612: case TYP:
1613: enterInner((ClassSymbol) e.sym);
1614: break;
1615: default:
1616: assert false;
1617: }
1618: }
1619: databuf.appendChar(fieldsCount);
1620: writeFields(c.members().elems);
1621: databuf.appendChar(methodsCount);
1622: writeMethods(c.members().elems);
1623:
1624: int acountIdx = beginAttrs();
1625: int acount = 0;
1626:
1627: boolean sigReq = typarams.length() != 0
1628: || super type.getTypeArguments().length() != 0;
1629: for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1630: sigReq = l.head.getTypeArguments().length() != 0;
1631: if (sigReq) {
1632: assert source.allowGenerics();
1633: int alenIdx = writeAttr(names.Signature);
1634: if (typarams.length() != 0)
1635: assembleParamsSig(typarams);
1636: assembleSig(super type);
1637: for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1638: assembleSig(l.head);
1639: databuf.appendChar(pool.put(sigbuf.toName(names)));
1640: sigbuf.reset();
1641: endAttr(alenIdx);
1642: acount++;
1643: }
1644:
1645: if (c.sourcefile != null && emitSourceFile) {
1646: int alenIdx = writeAttr(names.SourceFile);
1647: // WHM 6/29/1999: Strip file path prefix. We do it here at
1648: // the last possible moment because the sourcefile may be used
1649: // elsewhere in error diagnostics. Fixes 4241573.
1650: //databuf.appendChar(c.pool.put(c.sourcefile));
1651: String filename = c.sourcefile.toString();
1652: int sepIdx = filename.lastIndexOf(File.separatorChar);
1653: // Allow '/' as separator on all platforms, e.g., on Win32.
1654: int slashIdx = filename.lastIndexOf('/');
1655: if (slashIdx > sepIdx)
1656: sepIdx = slashIdx;
1657: if (sepIdx >= 0)
1658: filename = filename.substring(sepIdx + 1);
1659: databuf.appendChar(c.pool.put(names.fromString(filename)));
1660: endAttr(alenIdx);
1661: acount++;
1662: }
1663:
1664: if (genCrt) {
1665: // Append SourceID attribute
1666: int alenIdx = writeAttr(names.SourceID);
1667: databuf.appendChar(c.pool.put(names.fromString(Long
1668: .toString(getLastModified(c.sourcefile)))));
1669: endAttr(alenIdx);
1670: acount++;
1671: // Append CompilationID attribute
1672: alenIdx = writeAttr(names.CompilationID);
1673: databuf.appendChar(c.pool.put(names.fromString(Long
1674: .toString(System.currentTimeMillis()))));
1675: endAttr(alenIdx);
1676: acount++;
1677: }
1678:
1679: acount += writeFlagAttrs(c.flags());
1680: acount += writeJavaAnnotations(c.getAnnotationMirrors());
1681: acount += writeEnclosingMethodAttribute(c);
1682:
1683: poolbuf.appendInt(JAVA_MAGIC);
1684: poolbuf.appendChar(target.minorVersion);
1685: poolbuf.appendChar(target.majorVersion);
1686:
1687: writePool(c.pool);
1688:
1689: if (innerClasses != null) {
1690: writeInnerClasses();
1691: acount++;
1692: }
1693: endAttrs(acountIdx, acount);
1694:
1695: poolbuf.appendBytes(databuf.elems, 0, databuf.length);
1696: out.write(poolbuf.elems, 0, poolbuf.length);
1697:
1698: pool = c.pool = null; // to conserve space
1699: }
1700:
1701: int adjustFlags(final long flags) {
1702: int result = (int) flags;
1703: if ((flags & SYNTHETIC) != 0 && !target.useSyntheticFlag())
1704: result &= ~SYNTHETIC;
1705: if ((flags & ENUM) != 0 && !target.useEnumFlag())
1706: result &= ~ENUM;
1707: if ((flags & ANNOTATION) != 0 && !target.useAnnotationFlag())
1708: result &= ~ANNOTATION;
1709:
1710: if ((flags & BRIDGE) != 0 && target.useBridgeFlag())
1711: result |= ACC_BRIDGE;
1712: if ((flags & VARARGS) != 0 && target.useVarargsFlag())
1713: result |= ACC_VARARGS;
1714: return result;
1715: }
1716:
1717: long getLastModified(FileObject filename) {
1718: long mod = 0;
1719: try {
1720: mod = filename.getLastModified();
1721: } catch (SecurityException e) {
1722: throw new AssertionError(
1723: "CRT: couldn't get source file modification date: "
1724: + e.getMessage());
1725: }
1726: return mod;
1727: }
1728: }
|