Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java
38899 views
/*1* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.javap;2627import java.net.URI;28import java.text.DateFormat;29import java.util.Collection;30import java.util.Date;31import java.util.List;3233import com.sun.tools.classfile.AccessFlags;34import com.sun.tools.classfile.Attribute;35import com.sun.tools.classfile.Attributes;36import com.sun.tools.classfile.ClassFile;37import com.sun.tools.classfile.Code_attribute;38import com.sun.tools.classfile.ConstantPool;39import com.sun.tools.classfile.ConstantPoolException;40import com.sun.tools.classfile.ConstantValue_attribute;41import com.sun.tools.classfile.Descriptor;42import com.sun.tools.classfile.DescriptorException;43import com.sun.tools.classfile.Exceptions_attribute;44import com.sun.tools.classfile.Field;45import com.sun.tools.classfile.Method;46import com.sun.tools.classfile.Signature;47import com.sun.tools.classfile.Signature_attribute;48import com.sun.tools.classfile.SourceFile_attribute;49import com.sun.tools.classfile.Type;50import com.sun.tools.classfile.Type.ArrayType;51import com.sun.tools.classfile.Type.ClassSigType;52import com.sun.tools.classfile.Type.ClassType;53import com.sun.tools.classfile.Type.MethodType;54import com.sun.tools.classfile.Type.SimpleType;55import com.sun.tools.classfile.Type.TypeParamType;56import com.sun.tools.classfile.Type.WildcardType;5758import static com.sun.tools.classfile.AccessFlags.*;5960/*61* The main javap class to write the contents of a class file as text.62*63* <p><b>This is NOT part of any supported API.64* If you write code that depends on this, you do so at your own risk.65* This code and its internal interfaces are subject to change or66* deletion without notice.</b>67*/68public class ClassWriter extends BasicWriter {69static ClassWriter instance(Context context) {70ClassWriter instance = context.get(ClassWriter.class);71if (instance == null)72instance = new ClassWriter(context);73return instance;74}7576protected ClassWriter(Context context) {77super(context);78context.put(ClassWriter.class, this);79options = Options.instance(context);80attrWriter = AttributeWriter.instance(context);81codeWriter = CodeWriter.instance(context);82constantWriter = ConstantWriter.instance(context);83}8485void setDigest(String name, byte[] digest) {86this.digestName = name;87this.digest = digest;88}8990void setFile(URI uri) {91this.uri = uri;92}9394void setFileSize(int size) {95this.size = size;96}9798void setLastModified(long lastModified) {99this.lastModified = lastModified;100}101102protected ClassFile getClassFile() {103return classFile;104}105106protected void setClassFile(ClassFile cf) {107classFile = cf;108constant_pool = classFile.constant_pool;109}110111protected Method getMethod() {112return method;113}114115protected void setMethod(Method m) {116method = m;117}118119public void write(ClassFile cf) {120setClassFile(cf);121122if (options.sysInfo || options.verbose) {123if (uri != null) {124if (uri.getScheme().equals("file"))125println("Classfile " + uri.getPath());126else127println("Classfile " + uri);128}129indent(+1);130if (lastModified != -1) {131Date lm = new Date(lastModified);132DateFormat df = DateFormat.getDateInstance();133if (size > 0) {134println("Last modified " + df.format(lm) + "; size " + size + " bytes");135} else {136println("Last modified " + df.format(lm));137}138} else if (size > 0) {139println("Size " + size + " bytes");140}141if (digestName != null && digest != null) {142StringBuilder sb = new StringBuilder();143for (byte b: digest)144sb.append(String.format("%02x", b));145println(digestName + " checksum " + sb);146}147}148149Attribute sfa = cf.getAttribute(Attribute.SourceFile);150if (sfa instanceof SourceFile_attribute) {151println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");152}153154if (options.sysInfo || options.verbose) {155indent(-1);156}157158String name = getJavaName(classFile);159AccessFlags flags = cf.access_flags;160161writeModifiers(flags.getClassModifiers());162163if (classFile.isClass())164print("class ");165else if (classFile.isInterface())166print("interface ");167168print(name);169170Signature_attribute sigAttr = getSignature(cf.attributes);171if (sigAttr == null) {172// use info from class file header173if (classFile.isClass() && classFile.super_class != 0 ) {174String sn = getJavaSuperclassName(cf);175if (!sn.equals("java.lang.Object")) {176print(" extends ");177print(sn);178}179}180for (int i = 0; i < classFile.interfaces.length; i++) {181print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");182print(getJavaInterfaceName(classFile, i));183}184} else {185try {186Type t = sigAttr.getParsedSignature().getType(constant_pool);187JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface());188// The signature parser cannot disambiguate between a189// FieldType and a ClassSignatureType that only contains a superclass type.190if (t instanceof Type.ClassSigType) {191print(p.print(t));192} else if (options.verbose || !t.isObject()) {193print(" extends ");194print(p.print(t));195}196} catch (ConstantPoolException e) {197print(report(e));198}199}200201if (options.verbose) {202println();203indent(+1);204println("minor version: " + cf.minor_version);205println("major version: " + cf.major_version);206writeList("flags: ", flags.getClassFlags(), "\n");207indent(-1);208constantWriter.writeConstantPool();209} else {210print(" ");211}212213println("{");214indent(+1);215writeFields();216writeMethods();217indent(-1);218println("}");219220if (options.verbose) {221attrWriter.write(cf, cf.attributes, constant_pool);222}223}224// where225class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> {226boolean isInterface;227228JavaTypePrinter(boolean isInterface) {229this.isInterface = isInterface;230}231232String print(Type t) {233return t.accept(this, new StringBuilder()).toString();234}235236String printTypeArgs(List<? extends TypeParamType> typeParamTypes) {237StringBuilder builder = new StringBuilder();238appendIfNotEmpty(builder, "<", typeParamTypes, "> ");239return builder.toString();240}241242public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) {243sb.append(getJavaName(type.name));244return sb;245}246247public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) {248append(sb, type.elemType);249sb.append("[]");250return sb;251}252253public StringBuilder visitMethodType(MethodType type, StringBuilder sb) {254appendIfNotEmpty(sb, "<", type.typeParamTypes, "> ");255append(sb, type.returnType);256append(sb, " (", type.paramTypes, ")");257appendIfNotEmpty(sb, " throws ", type.throwsTypes, "");258return sb;259}260261public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) {262appendIfNotEmpty(sb, "<", type.typeParamTypes, ">");263if (isInterface) {264appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, "");265} else {266if (type.superclassType != null267&& (options.verbose || !type.superclassType.isObject())) {268sb.append(" extends ");269append(sb, type.superclassType);270}271appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, "");272}273return sb;274}275276public StringBuilder visitClassType(ClassType type, StringBuilder sb) {277if (type.outerType != null) {278append(sb, type.outerType);279sb.append(".");280}281sb.append(getJavaName(type.name));282appendIfNotEmpty(sb, "<", type.typeArgs, ">");283return sb;284}285286public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) {287sb.append(type.name);288String sep = " extends ";289if (type.classBound != null290&& (options.verbose || !type.classBound.isObject())) {291sb.append(sep);292append(sb, type.classBound);293sep = " & ";294}295if (type.interfaceBounds != null) {296for (Type bound: type.interfaceBounds) {297sb.append(sep);298append(sb, bound);299sep = " & ";300}301}302return sb;303}304305public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) {306switch (type.kind) {307case UNBOUNDED:308sb.append("?");309break;310case EXTENDS:311sb.append("? extends ");312append(sb, type.boundType);313break;314case SUPER:315sb.append("? super ");316append(sb, type.boundType);317break;318default:319throw new AssertionError();320}321return sb;322}323324private void append(StringBuilder sb, Type t) {325t.accept(this, sb);326}327328private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {329sb.append(prefix);330String sep = "";331for (Type t: list) {332sb.append(sep);333append(sb, t);334sep = ", ";335}336sb.append(suffix);337}338339private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {340if (!isEmpty(list))341append(sb, prefix, list, suffix);342}343344private boolean isEmpty(List<? extends Type> list) {345return (list == null || list.isEmpty());346}347}348349protected void writeFields() {350for (Field f: classFile.fields) {351writeField(f);352}353}354355protected void writeField(Field f) {356if (!options.checkAccess(f.access_flags))357return;358359AccessFlags flags = f.access_flags;360writeModifiers(flags.getFieldModifiers());361Signature_attribute sigAttr = getSignature(f.attributes);362if (sigAttr == null)363print(getJavaFieldType(f.descriptor));364else {365try {366Type t = sigAttr.getParsedSignature().getType(constant_pool);367print(getJavaName(t.toString()));368} catch (ConstantPoolException e) {369// report error?370// fall back on non-generic descriptor371print(getJavaFieldType(f.descriptor));372}373}374print(" ");375print(getFieldName(f));376if (options.showConstants) {377Attribute a = f.attributes.get(Attribute.ConstantValue);378if (a instanceof ConstantValue_attribute) {379print(" = ");380ConstantValue_attribute cv = (ConstantValue_attribute) a;381print(getConstantValue(f.descriptor, cv.constantvalue_index));382}383}384print(";");385println();386387indent(+1);388389boolean showBlank = false;390391if (options.showDescriptors)392println("descriptor: " + getValue(f.descriptor));393394if (options.verbose)395writeList("flags: ", flags.getFieldFlags(), "\n");396397if (options.showAllAttrs) {398for (Attribute attr: f.attributes)399attrWriter.write(f, attr, constant_pool);400showBlank = true;401}402403indent(-1);404405if (showBlank || options.showDisassembled || options.showLineAndLocalVariableTables)406println();407}408409protected void writeMethods() {410for (Method m: classFile.methods)411writeMethod(m);412setPendingNewline(false);413}414415protected void writeMethod(Method m) {416if (!options.checkAccess(m.access_flags))417return;418419method = m;420421AccessFlags flags = m.access_flags;422423Descriptor d;424Type.MethodType methodType;425List<? extends Type> methodExceptions;426427Signature_attribute sigAttr = getSignature(m.attributes);428if (sigAttr == null) {429d = m.descriptor;430methodType = null;431methodExceptions = null;432} else {433Signature methodSig = sigAttr.getParsedSignature();434d = methodSig;435try {436methodType = (Type.MethodType) methodSig.getType(constant_pool);437methodExceptions = methodType.throwsTypes;438if (methodExceptions != null && methodExceptions.isEmpty())439methodExceptions = null;440} catch (ConstantPoolException e) {441// report error?442// fall back on standard descriptor443methodType = null;444methodExceptions = null;445}446}447448writeModifiers(flags.getMethodModifiers());449if (methodType != null) {450print(new JavaTypePrinter(false).printTypeArgs(methodType.typeParamTypes));451}452if (getName(m).equals("<init>")) {453print(getJavaName(classFile));454print(getJavaParameterTypes(d, flags));455} else if (getName(m).equals("<clinit>")) {456print("{}");457} else {458print(getJavaReturnType(d));459print(" ");460print(getName(m));461print(getJavaParameterTypes(d, flags));462}463464Attribute e_attr = m.attributes.get(Attribute.Exceptions);465if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions466if (e_attr instanceof Exceptions_attribute) {467Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;468print(" throws ");469if (methodExceptions != null) { // use generic list if available470writeList("", methodExceptions, "");471} else {472for (int i = 0; i < exceptions.number_of_exceptions; i++) {473if (i > 0)474print(", ");475print(getJavaException(exceptions, i));476}477}478} else {479report("Unexpected or invalid value for Exceptions attribute");480}481}482483println(";");484485indent(+1);486487if (options.showDescriptors) {488println("descriptor: " + getValue(m.descriptor));489}490491if (options.verbose) {492writeList("flags: ", flags.getMethodFlags(), "\n");493}494495Code_attribute code = null;496Attribute c_attr = m.attributes.get(Attribute.Code);497if (c_attr != null) {498if (c_attr instanceof Code_attribute)499code = (Code_attribute) c_attr;500else501report("Unexpected or invalid value for Code attribute");502}503504if (options.showAllAttrs) {505Attribute[] attrs = m.attributes.attrs;506for (Attribute attr: attrs)507attrWriter.write(m, attr, constant_pool);508} else if (code != null) {509if (options.showDisassembled) {510println("Code:");511codeWriter.writeInstrs(code);512codeWriter.writeExceptionTable(code);513}514515if (options.showLineAndLocalVariableTables) {516attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);517attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);518}519}520521indent(-1);522523// set pendingNewline to write a newline before the next method (if any)524// if a separator is desired525setPendingNewline(526options.showDisassembled ||527options.showAllAttrs ||528options.showDescriptors ||529options.showLineAndLocalVariableTables ||530options.verbose);531}532533void writeModifiers(Collection<String> items) {534for (Object item: items) {535print(item);536print(" ");537}538}539540void writeList(String prefix, Collection<?> items, String suffix) {541print(prefix);542String sep = "";543for (Object item: items) {544print(sep);545print(item);546sep = ", ";547}548print(suffix);549}550551void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {552if (items != null && items.size() > 0)553writeList(prefix, items, suffix);554}555556Signature_attribute getSignature(Attributes attributes) {557return (Signature_attribute) attributes.get(Attribute.Signature);558}559560String adjustVarargs(AccessFlags flags, String params) {561if (flags.is(ACC_VARARGS)) {562int i = params.lastIndexOf("[]");563if (i > 0)564return params.substring(0, i) + "..." + params.substring(i+2);565}566567return params;568}569570String getJavaName(ClassFile cf) {571try {572return getJavaName(cf.getName());573} catch (ConstantPoolException e) {574return report(e);575}576}577578String getJavaSuperclassName(ClassFile cf) {579try {580return getJavaName(cf.getSuperclassName());581} catch (ConstantPoolException e) {582return report(e);583}584}585586String getJavaInterfaceName(ClassFile cf, int index) {587try {588return getJavaName(cf.getInterfaceName(index));589} catch (ConstantPoolException e) {590return report(e);591}592}593594String getJavaFieldType(Descriptor d) {595try {596return getJavaName(d.getFieldType(constant_pool));597} catch (ConstantPoolException e) {598return report(e);599} catch (DescriptorException e) {600return report(e);601}602}603604String getJavaReturnType(Descriptor d) {605try {606return getJavaName(d.getReturnType(constant_pool));607} catch (ConstantPoolException e) {608return report(e);609} catch (DescriptorException e) {610return report(e);611}612}613614String getJavaParameterTypes(Descriptor d, AccessFlags flags) {615try {616return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool)));617} catch (ConstantPoolException e) {618return report(e);619} catch (DescriptorException e) {620return report(e);621}622}623624String getJavaException(Exceptions_attribute attr, int index) {625try {626return getJavaName(attr.getException(index, constant_pool));627} catch (ConstantPoolException e) {628return report(e);629}630}631632String getValue(Descriptor d) {633try {634return d.getValue(constant_pool);635} catch (ConstantPoolException e) {636return report(e);637}638}639640String getFieldName(Field f) {641try {642return f.getName(constant_pool);643} catch (ConstantPoolException e) {644return report(e);645}646}647648String getName(Method m) {649try {650return m.getName(constant_pool);651} catch (ConstantPoolException e) {652return report(e);653}654}655656static String getJavaName(String name) {657return name.replace('/', '.');658}659660String getSourceFile(SourceFile_attribute attr) {661try {662return attr.getSourceFile(constant_pool);663} catch (ConstantPoolException e) {664return report(e);665}666}667668/**669* Get the value of an entry in the constant pool as a Java constant.670* Characters and booleans are represented by CONSTANT_Intgere entries.671* Character and string values are processed to escape characters outside672* the basic printable ASCII set.673* @param d the descriptor, giving the expected type of the constant674* @param index the index of the value in the constant pool675* @return a printable string containing the value of the constant.676*/677String getConstantValue(Descriptor d, int index) {678try {679ConstantPool.CPInfo cpInfo = constant_pool.get(index);680681switch (cpInfo.getTag()) {682case ConstantPool.CONSTANT_Integer: {683ConstantPool.CONSTANT_Integer_info info =684(ConstantPool.CONSTANT_Integer_info) cpInfo;685String t = d.getValue(constant_pool);686if (t.equals("C")) { // character687return getConstantCharValue((char) info.value);688} else if (t.equals("Z")) { // boolean689return String.valueOf(info.value == 1);690} else { // other: assume integer691return String.valueOf(info.value);692}693}694695case ConstantPool.CONSTANT_String: {696ConstantPool.CONSTANT_String_info info =697(ConstantPool.CONSTANT_String_info) cpInfo;698return getConstantStringValue(info.getString());699}700701default:702return constantWriter.stringValue(cpInfo);703}704} catch (ConstantPoolException e) {705return "#" + index;706}707}708709private String getConstantCharValue(char c) {710StringBuilder sb = new StringBuilder();711sb.append('\'');712sb.append(esc(c, '\''));713sb.append('\'');714return sb.toString();715}716717private String getConstantStringValue(String s) {718StringBuilder sb = new StringBuilder();719sb.append("\"");720for (int i = 0; i < s.length(); i++) {721sb.append(esc(s.charAt(i), '"'));722}723sb.append("\"");724return sb.toString();725}726727private String esc(char c, char quote) {728if (32 <= c && c <= 126 && c != quote)729return String.valueOf(c);730else switch (c) {731case '\b': return "\\b";732case '\n': return "\\n";733case '\t': return "\\t";734case '\f': return "\\f";735case '\r': return "\\r";736case '\\': return "\\\\";737case '\'': return "\\'";738case '\"': return "\\\"";739default: return String.format("\\u%04x", (int) c);740}741}742743private Options options;744private AttributeWriter attrWriter;745private CodeWriter codeWriter;746private ConstantWriter constantWriter;747private ClassFile classFile;748private URI uri;749private long lastModified;750private String digestName;751private byte[] digest;752private int size;753private ConstantPool constant_pool;754private Method method;755}756757758