1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javap/ClassWriter.java Tue Jun 03 13:26:47 2008 -0700 1.3 @@ -0,0 +1,488 @@ 1.4 +/* 1.5 + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Sun designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Sun in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.26 + * have any questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javap; 1.30 + 1.31 +import java.util.Collection; 1.32 +import java.util.List; 1.33 + 1.34 +import com.sun.tools.classfile.AccessFlags; 1.35 +import com.sun.tools.classfile.Attribute; 1.36 +import com.sun.tools.classfile.Attributes; 1.37 +import com.sun.tools.classfile.ClassFile; 1.38 +import com.sun.tools.classfile.Code_attribute; 1.39 +import com.sun.tools.classfile.ConstantPool; 1.40 +import com.sun.tools.classfile.ConstantPoolException; 1.41 +import com.sun.tools.classfile.Descriptor; 1.42 +import com.sun.tools.classfile.DescriptorException; 1.43 +import com.sun.tools.classfile.Exceptions_attribute; 1.44 +import com.sun.tools.classfile.Field; 1.45 +import com.sun.tools.classfile.Method; 1.46 +import com.sun.tools.classfile.Signature; 1.47 +import com.sun.tools.classfile.Signature_attribute; 1.48 +import com.sun.tools.classfile.SourceFile_attribute; 1.49 +import com.sun.tools.classfile.Type; 1.50 + 1.51 +import static com.sun.tools.classfile.AccessFlags.*; 1.52 + 1.53 +/* 1.54 + * The main javap class to write the contents of a class file as text. 1.55 + * 1.56 + * <p><b>This is NOT part of any API supported by Sun Microsystems. If 1.57 + * you write code that depends on this, you do so at your own risk. 1.58 + * This code and its internal interfaces are subject to change or 1.59 + * deletion without notice.</b> 1.60 + */ 1.61 +public class ClassWriter extends BasicWriter { 1.62 + static ClassWriter instance(Context context) { 1.63 + ClassWriter instance = context.get(ClassWriter.class); 1.64 + if (instance == null) 1.65 + instance = new ClassWriter(context); 1.66 + return instance; 1.67 + } 1.68 + 1.69 + protected ClassWriter(Context context) { 1.70 + super(context); 1.71 + context.put(ClassWriter.class, this); 1.72 + options = Options.instance(context); 1.73 + attrWriter = AttributeWriter.instance(context); 1.74 + codeWriter = CodeWriter.instance(context); 1.75 + constantWriter = ConstantWriter.instance(context); 1.76 + } 1.77 + 1.78 + ClassFile getClassFile() { 1.79 + return classFile; 1.80 + } 1.81 + 1.82 + Method getMethod() { 1.83 + return method; 1.84 + } 1.85 + 1.86 + public void write(ClassFile cf) { 1.87 + classFile = cf; 1.88 + constant_pool = classFile.constant_pool; 1.89 + 1.90 + Attribute sfa = cf.getAttribute(Attribute.SourceFile); 1.91 + if (sfa instanceof SourceFile_attribute) { 1.92 + println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\""); 1.93 + } 1.94 + 1.95 + String name = getJavaName(classFile); 1.96 + AccessFlags flags = cf.access_flags; 1.97 + 1.98 + writeModifiers(flags.getClassModifiers()); 1.99 + 1.100 + if (classFile.isClass()) 1.101 + print("class "); 1.102 + else if (classFile.isInterface()) 1.103 + print("interface "); 1.104 + 1.105 + print(name); 1.106 + 1.107 + Signature_attribute sigAttr = getSignature(cf.attributes); 1.108 + if (sigAttr == null) { 1.109 + // use info from class file header 1.110 + if (classFile.isClass()) { 1.111 + if (classFile.super_class != 0 ) { 1.112 + String sn = getJavaSuperclassName(cf); 1.113 + if (!sn.equals("java.lang.Object") || options.compat) { // BUG XXXXXXXX 1.114 + print(" extends "); 1.115 + print(sn); 1.116 + } 1.117 + } 1.118 + } 1.119 + for (int i = 0; i < classFile.interfaces.length; i++) { 1.120 + print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ","); 1.121 + print(getJavaInterfaceName(classFile, i)); 1.122 + } 1.123 + } else { 1.124 + try { 1.125 + Type t = sigAttr.getParsedSignature().getType(constant_pool); 1.126 + // The signature parser cannot disambiguate between a 1.127 + // FieldType and a ClassSignatureType that only contains a superclass type. 1.128 + if (t instanceof Type.ClassSigType) 1.129 + print(t); 1.130 + else if (!t.isObject()) { 1.131 + print(" extends "); 1.132 + print(t); 1.133 + } 1.134 + } catch (ConstantPoolException e) { 1.135 + print(report(e)); 1.136 + } 1.137 + } 1.138 + 1.139 + if (options.verbose) { 1.140 + println(); 1.141 + attrWriter.write(cf, cf.attributes, constant_pool); 1.142 + println(" minor version: " + cf.minor_version); 1.143 + println(" major version: " + cf.major_version); 1.144 + if (!options.compat) 1.145 + writeList(" flags: ", flags.getClassFlags(), NEWLINE); 1.146 + constantWriter.writeConstantPool(); 1.147 + println(); 1.148 + } else { 1.149 + if (!options.compat) 1.150 + print(" "); 1.151 + } 1.152 + 1.153 + println("{"); 1.154 + writeFields(); 1.155 + writeMethods(); 1.156 + println("}"); 1.157 + println(); 1.158 + } 1.159 + 1.160 + void writeFields() { 1.161 + for (Field f: classFile.fields) { 1.162 + writeField(f); 1.163 + } 1.164 + } 1.165 + 1.166 + void writeField(Field f) { 1.167 + if (!options.checkAccess(f.access_flags)) 1.168 + return; 1.169 + 1.170 + if (!(options.showLineAndLocalVariableTables 1.171 + || options.showDisassembled 1.172 + || options.verbose 1.173 + || options.showInternalSignatures 1.174 + || options.showAllAttrs)) { 1.175 + print(" "); 1.176 + } 1.177 + 1.178 + AccessFlags flags = f.access_flags; 1.179 + writeModifiers(flags.getFieldModifiers()); 1.180 + Signature_attribute sigAttr = getSignature(f.attributes); 1.181 + if (sigAttr == null) 1.182 + print(getFieldType(f.descriptor)); 1.183 + else { 1.184 + try { 1.185 + Type t = sigAttr.getParsedSignature().getType(constant_pool); 1.186 + print(t); 1.187 + } catch (ConstantPoolException e) { 1.188 + // report error? 1.189 + // fall back on non-generic descriptor 1.190 + print(getFieldType(f.descriptor)); 1.191 + } 1.192 + } 1.193 + print(" "); 1.194 + print(getFieldName(f)); 1.195 + print(";"); 1.196 + println(); 1.197 + 1.198 + if (options.showInternalSignatures) 1.199 + println(" Signature: " + getValue(f.descriptor)); 1.200 + 1.201 + if (options.verbose && !options.compat) 1.202 + writeList(" flags: ", flags.getFieldFlags(), NEWLINE); 1.203 + 1.204 + if (options.showAllAttrs) { 1.205 + for (Attribute attr: f.attributes) 1.206 + attrWriter.write(f, attr, constant_pool); 1.207 + println(); 1.208 + } 1.209 + 1.210 + if (options.showDisassembled || options.showLineAndLocalVariableTables) 1.211 + println(); 1.212 + } 1.213 + 1.214 + void writeMethods() { 1.215 + for (Method m: classFile.methods) 1.216 + writeMethod(m); 1.217 + } 1.218 + 1.219 + void writeMethod(Method m) { 1.220 + if (!options.checkAccess(m.access_flags)) 1.221 + return; 1.222 + 1.223 + method = m; 1.224 + 1.225 + if (!(options.showLineAndLocalVariableTables 1.226 + || options.showDisassembled 1.227 + || options.verbose 1.228 + || options.showInternalSignatures 1.229 + || options.showAllAttrs)) { 1.230 + print(" "); 1.231 + } 1.232 + 1.233 + AccessFlags flags = m.access_flags; 1.234 + 1.235 + Descriptor d; 1.236 + Type.MethodType methodType; 1.237 + List<? extends Type> methodExceptions; 1.238 + 1.239 + Signature_attribute sigAttr = getSignature(m.attributes); 1.240 + if (sigAttr == null) { 1.241 + d = m.descriptor; 1.242 + methodType = null; 1.243 + methodExceptions = null; 1.244 + } else { 1.245 + Signature methodSig = sigAttr.getParsedSignature(); 1.246 + d = methodSig; 1.247 + try { 1.248 + methodType = (Type.MethodType) methodSig.getType(constant_pool); 1.249 + methodExceptions = methodType.throwsTypes; 1.250 + if (methodExceptions != null && methodExceptions.size() == 0) 1.251 + methodExceptions = null; 1.252 + } catch (ConstantPoolException e) { 1.253 + // report error? 1.254 + // fall back on standard descriptor 1.255 + methodType = null; 1.256 + methodExceptions = null; 1.257 + } 1.258 + } 1.259 + 1.260 + writeModifiers(flags.getMethodModifiers()); 1.261 + if (methodType != null) { 1.262 + writeListIfNotEmpty("<", methodType.typeArgTypes, "> "); 1.263 + } 1.264 + if (getName(m).equals("<init>")) { 1.265 + print(getJavaName(classFile)); 1.266 + print(getParameterTypes(d, flags)); 1.267 + } else if (getName(m).equals("<clinit>")) { 1.268 + print("{}"); 1.269 + } else { 1.270 + print(getReturnType(d)); 1.271 + print(" "); 1.272 + print(getName(m)); 1.273 + print(getParameterTypes(d, flags)); 1.274 + } 1.275 + 1.276 + Attribute e_attr = m.attributes.get(Attribute.Exceptions); 1.277 + if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions 1.278 + if (e_attr instanceof Exceptions_attribute) { 1.279 + Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; 1.280 + if (options.compat) { // Bug XXXXXXX whitespace 1.281 + if (!(options.showLineAndLocalVariableTables 1.282 + || options.showDisassembled 1.283 + || options.verbose 1.284 + || options.showInternalSignatures 1.285 + || options.showAllAttrs)) { 1.286 + print(" "); 1.287 + } 1.288 + print(" "); 1.289 + } 1.290 + print(" throws "); 1.291 + if (methodExceptions != null) { // use generic list if available 1.292 + writeList("", methodExceptions, ""); 1.293 + } else { 1.294 + for (int i = 0; i < exceptions.number_of_exceptions; i++) { 1.295 + if (i > 0) 1.296 + print(", "); 1.297 + print(attrWriter.getJavaException(exceptions, i)); 1.298 + } 1.299 + } 1.300 + } else { 1.301 + report("Unexpected or invalid value for Exceptions attribute"); 1.302 + } 1.303 + } 1.304 + 1.305 + print(";"); 1.306 + println(); 1.307 + 1.308 + if (options.showInternalSignatures) 1.309 + println(" Signature: " + getValue(m.descriptor)); 1.310 + 1.311 + if (options.verbose && !options.compat) 1.312 + writeList(" flags: ", flags.getMethodFlags(), NEWLINE); 1.313 + 1.314 + Code_attribute code = null; 1.315 + Attribute c_attr = m.attributes.get(Attribute.Code); 1.316 + if (c_attr != null) { 1.317 + if (c_attr instanceof Code_attribute) 1.318 + code = (Code_attribute) c_attr; 1.319 + else 1.320 + report("Unexpected or invalid value for Code attribute"); 1.321 + } 1.322 + 1.323 + if (options.showDisassembled && !options.showAllAttrs) { 1.324 + if (code != null) { 1.325 + println(" Code:"); 1.326 + codeWriter.writeInstrs(code); 1.327 + codeWriter.writeExceptionTable(code); 1.328 + } 1.329 + println(); 1.330 + } 1.331 + 1.332 + if (options.showLineAndLocalVariableTables) { 1.333 + if (code != null) 1.334 + attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool); 1.335 + println(); 1.336 + if (code != null) 1.337 + attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool); 1.338 + println(); 1.339 + println(); 1.340 + } 1.341 + 1.342 + if (options.showAllAttrs) { 1.343 + Attribute[] attrs = m.attributes.attrs; 1.344 + for (Attribute attr: attrs) 1.345 + attrWriter.write(m, attr, constant_pool); 1.346 + 1.347 +// // the following condition is to mimic old javap 1.348 +// if (!(attrs.length > 0 && 1.349 +// attrs[attrs.length - 1] instanceof Exceptions_attribute)) 1.350 + println(); 1.351 + } 1.352 + } 1.353 + 1.354 + void writeModifiers(Collection<String> items) { 1.355 + for (Object item: items) { 1.356 + print(item); 1.357 + print(" "); 1.358 + } 1.359 + } 1.360 + 1.361 + void writeList(String prefix, Collection<?> items, String suffix) { 1.362 + print(prefix); 1.363 + String sep = ""; 1.364 + for (Object item: items) { 1.365 + print(sep); 1.366 + print(item); 1.367 + sep = ", "; 1.368 + } 1.369 + print(suffix); 1.370 + } 1.371 + 1.372 + void writeListIfNotEmpty(String prefix, List<?> items, String suffix) { 1.373 + if (items != null && items.size() > 0) 1.374 + writeList(prefix, items, suffix); 1.375 + } 1.376 + 1.377 + Signature_attribute getSignature(Attributes attributes) { 1.378 + if (options.compat) // javap does not recognize recent attributes 1.379 + return null; 1.380 + return (Signature_attribute) attributes.get(Attribute.Signature); 1.381 + } 1.382 + 1.383 + String adjustVarargs(AccessFlags flags, String params) { 1.384 + if (flags.is(ACC_VARARGS) && !options.compat) { 1.385 + int i = params.lastIndexOf("[]"); 1.386 + if (i > 0) 1.387 + return params.substring(0, i) + "..." + params.substring(i+2); 1.388 + } 1.389 + 1.390 + return params; 1.391 + } 1.392 + 1.393 + String getJavaName(ClassFile cf) { 1.394 + try { 1.395 + return getJavaName(cf.getName()); 1.396 + } catch (ConstantPoolException e) { 1.397 + return report(e); 1.398 + } 1.399 + } 1.400 + 1.401 + String getJavaSuperclassName(ClassFile cf) { 1.402 + try { 1.403 + return getJavaName(cf.getSuperclassName()); 1.404 + } catch (ConstantPoolException e) { 1.405 + return report(e); 1.406 + } 1.407 + } 1.408 + 1.409 + String getJavaInterfaceName(ClassFile cf, int index) { 1.410 + try { 1.411 + return getJavaName(cf.getInterfaceName(index)); 1.412 + } catch (ConstantPoolException e) { 1.413 + return report(e); 1.414 + } 1.415 + } 1.416 + 1.417 + String getFieldType(Descriptor d) { 1.418 + try { 1.419 + return d.getFieldType(constant_pool); 1.420 + } catch (ConstantPoolException e) { 1.421 + return report(e); 1.422 + } catch (DescriptorException e) { 1.423 + return report(e); 1.424 + } 1.425 + } 1.426 + 1.427 + String getReturnType(Descriptor d) { 1.428 + try { 1.429 + return d.getReturnType(constant_pool); 1.430 + } catch (ConstantPoolException e) { 1.431 + return report(e); 1.432 + } catch (DescriptorException e) { 1.433 + return report(e); 1.434 + } 1.435 + } 1.436 + 1.437 + String getParameterTypes(Descriptor d, AccessFlags flags) { 1.438 + try { 1.439 + return adjustVarargs(flags, d.getParameterTypes(constant_pool)); 1.440 + } catch (ConstantPoolException e) { 1.441 + return report(e); 1.442 + } catch (DescriptorException e) { 1.443 + return report(e); 1.444 + } 1.445 + } 1.446 + 1.447 + String getValue(Descriptor d) { 1.448 + try { 1.449 + return d.getValue(constant_pool); 1.450 + } catch (ConstantPoolException e) { 1.451 + return report(e); 1.452 + } 1.453 + } 1.454 + 1.455 + String getFieldName(Field f) { 1.456 + try { 1.457 + return f.getName(constant_pool); 1.458 + } catch (ConstantPoolException e) { 1.459 + return report(e); 1.460 + } 1.461 + } 1.462 + 1.463 + String getName(Method m) { 1.464 + try { 1.465 + return m.getName(constant_pool); 1.466 + } catch (ConstantPoolException e) { 1.467 + return report(e); 1.468 + } 1.469 + } 1.470 + 1.471 + static String getJavaName(String name) { 1.472 + return name.replace('/', '.'); 1.473 + } 1.474 + 1.475 + String getSourceFile(SourceFile_attribute attr) { 1.476 + try { 1.477 + return attr.getSourceFile(constant_pool); 1.478 + } catch (ConstantPoolException e) { 1.479 + return report(e); 1.480 + } 1.481 + } 1.482 + 1.483 + private Options options; 1.484 + private AttributeWriter attrWriter; 1.485 + private CodeWriter codeWriter; 1.486 + private ConstantWriter constantWriter; 1.487 + private ClassFile classFile; 1.488 + private ConstantPool constant_pool; 1.489 + private Method method; 1.490 + private static final String NEWLINE = System.getProperty("line.separator", "\n"); 1.491 +}