Mon, 25 Mar 2013 16:55:14 -0700
8010521: jdk8 l10n resource file translation update 2
Reviewed-by: naoto, yhuang
jjg@46 | 1 | /* |
jjh@1478 | 2 | * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. |
jjg@46 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jjg@46 | 4 | * |
jjg@46 | 5 | * This code is free software; you can redistribute it and/or modify it |
jjg@46 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohair@554 | 7 | * published by the Free Software Foundation. Oracle designates this |
jjg@46 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@554 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
jjg@46 | 10 | * |
jjg@46 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jjg@46 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jjg@46 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jjg@46 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
jjg@46 | 15 | * accompanied this code). |
jjg@46 | 16 | * |
jjg@46 | 17 | * You should have received a copy of the GNU General Public License version |
jjg@46 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
jjg@46 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jjg@46 | 20 | * |
ohair@554 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@554 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@554 | 23 | * questions. |
jjg@46 | 24 | */ |
jjg@46 | 25 | |
jjg@46 | 26 | package com.sun.tools.javap; |
jjg@46 | 27 | |
jjg@88 | 28 | import java.net.URI; |
jjg@283 | 29 | import java.text.DateFormat; |
jjg@46 | 30 | import java.util.Collection; |
jjg@283 | 31 | import java.util.Date; |
jjg@46 | 32 | import java.util.List; |
jjg@46 | 33 | |
jjg@46 | 34 | import com.sun.tools.classfile.AccessFlags; |
jjg@46 | 35 | import com.sun.tools.classfile.Attribute; |
jjg@46 | 36 | import com.sun.tools.classfile.Attributes; |
jjg@46 | 37 | import com.sun.tools.classfile.ClassFile; |
jjg@46 | 38 | import com.sun.tools.classfile.Code_attribute; |
jjg@46 | 39 | import com.sun.tools.classfile.ConstantPool; |
jjg@46 | 40 | import com.sun.tools.classfile.ConstantPoolException; |
jjg@87 | 41 | import com.sun.tools.classfile.ConstantValue_attribute; |
jjg@46 | 42 | import com.sun.tools.classfile.Descriptor; |
jjg@46 | 43 | import com.sun.tools.classfile.DescriptorException; |
jjg@46 | 44 | import com.sun.tools.classfile.Exceptions_attribute; |
jjg@46 | 45 | import com.sun.tools.classfile.Field; |
jjg@46 | 46 | import com.sun.tools.classfile.Method; |
jjg@46 | 47 | import com.sun.tools.classfile.Signature; |
jjg@46 | 48 | import com.sun.tools.classfile.Signature_attribute; |
jjg@46 | 49 | import com.sun.tools.classfile.SourceFile_attribute; |
jjg@46 | 50 | import com.sun.tools.classfile.Type; |
jjg@953 | 51 | import com.sun.tools.classfile.Type.ArrayType; |
jjg@953 | 52 | import com.sun.tools.classfile.Type.ClassSigType; |
jjg@953 | 53 | import com.sun.tools.classfile.Type.ClassType; |
jjg@953 | 54 | import com.sun.tools.classfile.Type.MethodType; |
jjg@953 | 55 | import com.sun.tools.classfile.Type.SimpleType; |
jjg@953 | 56 | import com.sun.tools.classfile.Type.TypeParamType; |
jjg@953 | 57 | import com.sun.tools.classfile.Type.WildcardType; |
jjg@46 | 58 | |
jjg@46 | 59 | import static com.sun.tools.classfile.AccessFlags.*; |
jjg@46 | 60 | |
jjg@46 | 61 | /* |
jjg@46 | 62 | * The main javap class to write the contents of a class file as text. |
jjg@46 | 63 | * |
jjg@581 | 64 | * <p><b>This is NOT part of any supported API. |
jjg@581 | 65 | * If you write code that depends on this, you do so at your own risk. |
jjg@46 | 66 | * This code and its internal interfaces are subject to change or |
jjg@46 | 67 | * deletion without notice.</b> |
jjg@46 | 68 | */ |
jjg@46 | 69 | public class ClassWriter extends BasicWriter { |
jjg@46 | 70 | static ClassWriter instance(Context context) { |
jjg@46 | 71 | ClassWriter instance = context.get(ClassWriter.class); |
jjg@46 | 72 | if (instance == null) |
jjg@46 | 73 | instance = new ClassWriter(context); |
jjg@46 | 74 | return instance; |
jjg@46 | 75 | } |
jjg@46 | 76 | |
jjg@46 | 77 | protected ClassWriter(Context context) { |
jjg@46 | 78 | super(context); |
jjg@46 | 79 | context.put(ClassWriter.class, this); |
jjg@46 | 80 | options = Options.instance(context); |
jjg@46 | 81 | attrWriter = AttributeWriter.instance(context); |
jjg@46 | 82 | codeWriter = CodeWriter.instance(context); |
jjg@46 | 83 | constantWriter = ConstantWriter.instance(context); |
jjg@46 | 84 | } |
jjg@46 | 85 | |
jjg@88 | 86 | void setDigest(String name, byte[] digest) { |
jjg@88 | 87 | this.digestName = name; |
jjg@88 | 88 | this.digest = digest; |
jjg@88 | 89 | } |
jjg@88 | 90 | |
jjg@88 | 91 | void setFile(URI uri) { |
jjg@88 | 92 | this.uri = uri; |
jjg@88 | 93 | } |
jjg@88 | 94 | |
jjg@88 | 95 | void setFileSize(int size) { |
jjg@88 | 96 | this.size = size; |
jjg@88 | 97 | } |
jjg@88 | 98 | |
jjg@88 | 99 | void setLastModified(long lastModified) { |
jjg@88 | 100 | this.lastModified = lastModified; |
jjg@88 | 101 | } |
jjg@88 | 102 | |
jjg@300 | 103 | protected ClassFile getClassFile() { |
jjg@46 | 104 | return classFile; |
jjg@46 | 105 | } |
jjg@46 | 106 | |
jjg@300 | 107 | protected void setClassFile(ClassFile cf) { |
jjg@300 | 108 | classFile = cf; |
jjg@300 | 109 | constant_pool = classFile.constant_pool; |
jjg@300 | 110 | } |
jjg@300 | 111 | |
jjg@300 | 112 | protected Method getMethod() { |
jjg@46 | 113 | return method; |
jjg@46 | 114 | } |
jjg@46 | 115 | |
jjg@300 | 116 | protected void setMethod(Method m) { |
jjg@300 | 117 | method = m; |
jjg@300 | 118 | } |
jjg@300 | 119 | |
jjg@46 | 120 | public void write(ClassFile cf) { |
jjg@300 | 121 | setClassFile(cf); |
jjg@46 | 122 | |
jjg@88 | 123 | if ((options.sysInfo || options.verbose) && !options.compat) { |
jjg@88 | 124 | if (uri != null) { |
jjg@88 | 125 | if (uri.getScheme().equals("file")) |
jjg@88 | 126 | println("Classfile " + uri.getPath()); |
jjg@88 | 127 | else |
jjg@88 | 128 | println("Classfile " + uri); |
jjg@88 | 129 | } |
jjg@348 | 130 | indent(+1); |
jjg@88 | 131 | if (lastModified != -1) { |
jjg@88 | 132 | Date lm = new Date(lastModified); |
jjg@88 | 133 | DateFormat df = DateFormat.getDateInstance(); |
jjg@88 | 134 | if (size > 0) { |
jjg@88 | 135 | println("Last modified " + df.format(lm) + "; size " + size + " bytes"); |
jjg@88 | 136 | } else { |
jjg@88 | 137 | println("Last modified " + df.format(lm)); |
jjg@88 | 138 | } |
jjg@88 | 139 | } else if (size > 0) { |
jjg@88 | 140 | println("Size " + size + " bytes"); |
jjg@88 | 141 | } |
jjg@88 | 142 | if (digestName != null && digest != null) { |
jjg@88 | 143 | StringBuilder sb = new StringBuilder(); |
jjg@88 | 144 | for (byte b: digest) |
jjg@88 | 145 | sb.append(String.format("%02x", b)); |
jjg@88 | 146 | println(digestName + " checksum " + sb); |
jjg@88 | 147 | } |
jjg@88 | 148 | } |
jjg@88 | 149 | |
jjg@46 | 150 | Attribute sfa = cf.getAttribute(Attribute.SourceFile); |
jjg@46 | 151 | if (sfa instanceof SourceFile_attribute) { |
jjg@46 | 152 | println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\""); |
jjg@46 | 153 | } |
jjg@46 | 154 | |
jjg@348 | 155 | if ((options.sysInfo || options.verbose) && !options.compat) { |
jjg@348 | 156 | indent(-1); |
jjg@348 | 157 | } |
jjg@348 | 158 | |
jjg@46 | 159 | String name = getJavaName(classFile); |
jjg@46 | 160 | AccessFlags flags = cf.access_flags; |
jjg@46 | 161 | |
jjg@46 | 162 | writeModifiers(flags.getClassModifiers()); |
jjg@46 | 163 | |
jjg@46 | 164 | if (classFile.isClass()) |
jjg@46 | 165 | print("class "); |
jjg@46 | 166 | else if (classFile.isInterface()) |
jjg@46 | 167 | print("interface "); |
jjg@46 | 168 | |
jjg@46 | 169 | print(name); |
jjg@46 | 170 | |
jjg@46 | 171 | Signature_attribute sigAttr = getSignature(cf.attributes); |
jjg@46 | 172 | if (sigAttr == null) { |
jjg@46 | 173 | // use info from class file header |
jjg@65 | 174 | if (classFile.isClass() && classFile.super_class != 0 ) { |
jjg@65 | 175 | String sn = getJavaSuperclassName(cf); |
jjg@953 | 176 | if (!sn.equals("java.lang.Object")) { |
jjg@953 | 177 | print(" extends "); |
jjg@953 | 178 | print(sn); |
jjg@953 | 179 | } |
jjg@46 | 180 | } |
jjg@46 | 181 | for (int i = 0; i < classFile.interfaces.length; i++) { |
jjg@46 | 182 | print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ","); |
jjg@46 | 183 | print(getJavaInterfaceName(classFile, i)); |
jjg@46 | 184 | } |
jjg@46 | 185 | } else { |
jjg@46 | 186 | try { |
jjg@46 | 187 | Type t = sigAttr.getParsedSignature().getType(constant_pool); |
jjg@953 | 188 | JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface()); |
jjg@46 | 189 | // The signature parser cannot disambiguate between a |
jjg@46 | 190 | // FieldType and a ClassSignatureType that only contains a superclass type. |
jjg@953 | 191 | if (t instanceof Type.ClassSigType) { |
jjg@953 | 192 | print(p.print(t)); |
jjg@953 | 193 | } else if (options.verbose || !t.isObject()) { |
jjg@46 | 194 | print(" extends "); |
jjg@953 | 195 | print(p.print(t)); |
jjg@46 | 196 | } |
jjg@46 | 197 | } catch (ConstantPoolException e) { |
jjg@46 | 198 | print(report(e)); |
jjg@46 | 199 | } |
jjg@46 | 200 | } |
jjg@46 | 201 | |
jjg@46 | 202 | if (options.verbose) { |
jjg@46 | 203 | println(); |
jjg@348 | 204 | indent(+1); |
jjg@46 | 205 | attrWriter.write(cf, cf.attributes, constant_pool); |
jjg@348 | 206 | println("minor version: " + cf.minor_version); |
jjg@348 | 207 | println("major version: " + cf.major_version); |
jjg@46 | 208 | if (!options.compat) |
jjh@1478 | 209 | writeList("flags: ", flags.getClassFlags(), "\n"); |
jjg@348 | 210 | indent(-1); |
jjg@46 | 211 | constantWriter.writeConstantPool(); |
jjg@46 | 212 | } else { |
jjg@348 | 213 | print(" "); |
jjg@46 | 214 | } |
jjg@46 | 215 | |
jjg@46 | 216 | println("{"); |
jjg@348 | 217 | indent(+1); |
jjg@46 | 218 | writeFields(); |
jjg@46 | 219 | writeMethods(); |
jjg@348 | 220 | indent(-1); |
jjg@46 | 221 | println("}"); |
jjg@46 | 222 | } |
jjg@953 | 223 | // where |
jjg@953 | 224 | class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> { |
jjg@953 | 225 | boolean isInterface; |
jjg@953 | 226 | |
jjg@953 | 227 | JavaTypePrinter(boolean isInterface) { |
jjg@953 | 228 | this.isInterface = isInterface; |
jjg@953 | 229 | } |
jjg@953 | 230 | |
jjg@953 | 231 | String print(Type t) { |
jjg@953 | 232 | return t.accept(this, new StringBuilder()).toString(); |
jjg@953 | 233 | } |
jjg@953 | 234 | |
jjg@953 | 235 | public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) { |
jjg@953 | 236 | sb.append(getJavaName(type.name)); |
jjg@953 | 237 | return sb; |
jjg@953 | 238 | } |
jjg@953 | 239 | |
jjg@953 | 240 | public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) { |
jjg@953 | 241 | append(sb, type.elemType); |
jjg@953 | 242 | sb.append("[]"); |
jjg@953 | 243 | return sb; |
jjg@953 | 244 | } |
jjg@953 | 245 | |
jjg@953 | 246 | public StringBuilder visitMethodType(MethodType type, StringBuilder sb) { |
jjg@953 | 247 | appendIfNotEmpty(sb, "<", type.typeParamTypes, "> "); |
jjg@953 | 248 | append(sb, type.returnType); |
jjg@953 | 249 | append(sb, " (", type.paramTypes, ")"); |
jjg@953 | 250 | appendIfNotEmpty(sb, " throws ", type.throwsTypes, ""); |
jjg@953 | 251 | return sb; |
jjg@953 | 252 | } |
jjg@953 | 253 | |
jjg@953 | 254 | public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) { |
jjg@953 | 255 | appendIfNotEmpty(sb, "<", type.typeParamTypes, ">"); |
jjg@953 | 256 | if (isInterface) { |
jjg@953 | 257 | appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, ""); |
jjg@953 | 258 | } else { |
jjg@953 | 259 | if (type.superclassType != null |
jjg@953 | 260 | && (options.verbose || !type.superclassType.isObject())) { |
jjg@953 | 261 | sb.append(" extends "); |
jjg@953 | 262 | append(sb, type.superclassType); |
jjg@953 | 263 | } |
jjg@953 | 264 | appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, ""); |
jjg@953 | 265 | } |
jjg@953 | 266 | return sb; |
jjg@953 | 267 | } |
jjg@953 | 268 | |
jjg@953 | 269 | public StringBuilder visitClassType(ClassType type, StringBuilder sb) { |
jjg@953 | 270 | if (type.outerType != null) { |
jjg@953 | 271 | append(sb, type.outerType); |
jjg@953 | 272 | sb.append("."); |
jjg@953 | 273 | } |
jjg@953 | 274 | sb.append(getJavaName(type.name)); |
jjg@953 | 275 | appendIfNotEmpty(sb, "<", type.typeArgs, ">"); |
jjg@953 | 276 | return sb; |
jjg@953 | 277 | } |
jjg@953 | 278 | |
jjg@953 | 279 | public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) { |
jjg@953 | 280 | sb.append(type.name); |
jjg@953 | 281 | String sep = " extends "; |
jjg@953 | 282 | if (type.classBound != null |
jjg@953 | 283 | && (options.verbose || !type.classBound.isObject())) { |
jjg@953 | 284 | sb.append(sep); |
jjg@953 | 285 | append(sb, type.classBound); |
jjg@953 | 286 | sep = " & "; |
jjg@953 | 287 | } |
jjg@953 | 288 | if (type.interfaceBounds != null) { |
jjg@953 | 289 | for (Type bound: type.interfaceBounds) { |
jjg@953 | 290 | sb.append(sep); |
jjg@953 | 291 | append(sb, bound); |
jjg@953 | 292 | sep = " & "; |
jjg@953 | 293 | } |
jjg@953 | 294 | } |
jjg@953 | 295 | return sb; |
jjg@953 | 296 | } |
jjg@953 | 297 | |
jjg@953 | 298 | public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) { |
jjg@953 | 299 | switch (type.kind) { |
jjg@953 | 300 | case UNBOUNDED: |
jjg@953 | 301 | sb.append("?"); |
jjg@953 | 302 | break; |
jjg@953 | 303 | case EXTENDS: |
jjg@953 | 304 | sb.append("? extends "); |
jjg@953 | 305 | append(sb, type.boundType); |
jjg@953 | 306 | break; |
jjg@953 | 307 | case SUPER: |
jjg@953 | 308 | sb.append("? super "); |
jjg@953 | 309 | append(sb, type.boundType); |
jjg@953 | 310 | break; |
jjg@953 | 311 | default: |
jjg@953 | 312 | throw new AssertionError(); |
jjg@953 | 313 | } |
jjg@953 | 314 | return sb; |
jjg@953 | 315 | } |
jjg@953 | 316 | |
jjg@953 | 317 | private void append(StringBuilder sb, Type t) { |
jjg@953 | 318 | t.accept(this, sb); |
jjg@953 | 319 | } |
jjg@953 | 320 | |
jjg@953 | 321 | private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) { |
jjg@953 | 322 | sb.append(prefix); |
jjg@953 | 323 | String sep = ""; |
jjg@953 | 324 | for (Type t: list) { |
jjg@953 | 325 | sb.append(sep); |
jjg@953 | 326 | append(sb, t); |
jjg@953 | 327 | sep = ", "; |
jjg@953 | 328 | } |
jjg@953 | 329 | sb.append(suffix); |
jjg@953 | 330 | } |
jjg@953 | 331 | |
jjg@953 | 332 | private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) { |
jjg@953 | 333 | if (!isEmpty(list)) |
jjg@953 | 334 | append(sb, prefix, list, suffix); |
jjg@953 | 335 | } |
jjg@953 | 336 | |
jjg@953 | 337 | private boolean isEmpty(List<? extends Type> list) { |
jjg@953 | 338 | return (list == null || list.isEmpty()); |
jjg@953 | 339 | } |
jjg@953 | 340 | } |
jjg@46 | 341 | |
jjg@300 | 342 | protected void writeFields() { |
jjg@46 | 343 | for (Field f: classFile.fields) { |
jjg@46 | 344 | writeField(f); |
jjg@46 | 345 | } |
jjg@46 | 346 | } |
jjg@46 | 347 | |
jjg@300 | 348 | protected void writeField(Field f) { |
jjg@46 | 349 | if (!options.checkAccess(f.access_flags)) |
jjg@46 | 350 | return; |
jjg@46 | 351 | |
jjg@46 | 352 | AccessFlags flags = f.access_flags; |
jjg@46 | 353 | writeModifiers(flags.getFieldModifiers()); |
jjg@46 | 354 | Signature_attribute sigAttr = getSignature(f.attributes); |
jjg@46 | 355 | if (sigAttr == null) |
jjg@528 | 356 | print(getJavaFieldType(f.descriptor)); |
jjg@46 | 357 | else { |
jjg@46 | 358 | try { |
jjg@46 | 359 | Type t = sigAttr.getParsedSignature().getType(constant_pool); |
jjg@528 | 360 | print(getJavaName(t.toString())); |
jjg@46 | 361 | } catch (ConstantPoolException e) { |
jjg@46 | 362 | // report error? |
jjg@46 | 363 | // fall back on non-generic descriptor |
jjg@528 | 364 | print(getJavaFieldType(f.descriptor)); |
jjg@46 | 365 | } |
jjg@46 | 366 | } |
jjg@46 | 367 | print(" "); |
jjg@46 | 368 | print(getFieldName(f)); |
jjg@87 | 369 | if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents |
jjg@87 | 370 | Attribute a = f.attributes.get(Attribute.ConstantValue); |
jjg@87 | 371 | if (a instanceof ConstantValue_attribute) { |
jjg@87 | 372 | print(" = "); |
jjg@87 | 373 | ConstantValue_attribute cv = (ConstantValue_attribute) a; |
jjg@87 | 374 | print(getConstantValue(f.descriptor, cv.constantvalue_index)); |
jjg@87 | 375 | } |
jjg@87 | 376 | } |
jjg@46 | 377 | print(";"); |
jjg@46 | 378 | println(); |
jjg@46 | 379 | |
jjg@348 | 380 | indent(+1); |
jjg@348 | 381 | |
jjg@1578 | 382 | if (options.showDescriptors) |
jjg@1578 | 383 | println("descriptor: " + getValue(f.descriptor)); |
jjg@46 | 384 | |
jjg@46 | 385 | if (options.verbose && !options.compat) |
jjh@1478 | 386 | writeList("flags: ", flags.getFieldFlags(), "\n"); |
jjg@46 | 387 | |
jjg@46 | 388 | if (options.showAllAttrs) { |
jjg@46 | 389 | for (Attribute attr: f.attributes) |
jjg@46 | 390 | attrWriter.write(f, attr, constant_pool); |
jjg@46 | 391 | println(); |
jjg@46 | 392 | } |
jjg@46 | 393 | |
jjg@348 | 394 | indent(-1); |
jjg@348 | 395 | |
jjg@46 | 396 | if (options.showDisassembled || options.showLineAndLocalVariableTables) |
jjg@46 | 397 | println(); |
jjg@46 | 398 | } |
jjg@46 | 399 | |
jjg@300 | 400 | protected void writeMethods() { |
jjg@46 | 401 | for (Method m: classFile.methods) |
jjg@46 | 402 | writeMethod(m); |
jjg@348 | 403 | setPendingNewline(false); |
jjg@46 | 404 | } |
jjg@46 | 405 | |
jjg@300 | 406 | protected void writeMethod(Method m) { |
jjg@46 | 407 | if (!options.checkAccess(m.access_flags)) |
jjg@46 | 408 | return; |
jjg@46 | 409 | |
jjg@46 | 410 | method = m; |
jjg@46 | 411 | |
jjg@46 | 412 | AccessFlags flags = m.access_flags; |
jjg@46 | 413 | |
jjg@46 | 414 | Descriptor d; |
jjg@46 | 415 | Type.MethodType methodType; |
jjg@46 | 416 | List<? extends Type> methodExceptions; |
jjg@46 | 417 | |
jjg@46 | 418 | Signature_attribute sigAttr = getSignature(m.attributes); |
jjg@46 | 419 | if (sigAttr == null) { |
jjg@46 | 420 | d = m.descriptor; |
jjg@46 | 421 | methodType = null; |
jjg@46 | 422 | methodExceptions = null; |
jjg@46 | 423 | } else { |
jjg@46 | 424 | Signature methodSig = sigAttr.getParsedSignature(); |
jjg@46 | 425 | d = methodSig; |
jjg@46 | 426 | try { |
jjg@46 | 427 | methodType = (Type.MethodType) methodSig.getType(constant_pool); |
jjg@46 | 428 | methodExceptions = methodType.throwsTypes; |
jjg@953 | 429 | if (methodExceptions != null && methodExceptions.isEmpty()) |
jjg@46 | 430 | methodExceptions = null; |
jjg@46 | 431 | } catch (ConstantPoolException e) { |
jjg@46 | 432 | // report error? |
jjg@46 | 433 | // fall back on standard descriptor |
jjg@46 | 434 | methodType = null; |
jjg@46 | 435 | methodExceptions = null; |
jjg@46 | 436 | } |
jjg@46 | 437 | } |
jjg@46 | 438 | |
jjg@46 | 439 | writeModifiers(flags.getMethodModifiers()); |
jjg@46 | 440 | if (methodType != null) { |
jjg@427 | 441 | writeListIfNotEmpty("<", methodType.typeParamTypes, "> "); |
jjg@46 | 442 | } |
jjg@46 | 443 | if (getName(m).equals("<init>")) { |
jjg@46 | 444 | print(getJavaName(classFile)); |
jjg@528 | 445 | print(getJavaParameterTypes(d, flags)); |
jjg@46 | 446 | } else if (getName(m).equals("<clinit>")) { |
jjg@46 | 447 | print("{}"); |
jjg@46 | 448 | } else { |
jjg@528 | 449 | print(getJavaReturnType(d)); |
jjg@46 | 450 | print(" "); |
jjg@46 | 451 | print(getName(m)); |
jjg@528 | 452 | print(getJavaParameterTypes(d, flags)); |
jjg@46 | 453 | } |
jjg@46 | 454 | |
jjg@46 | 455 | Attribute e_attr = m.attributes.get(Attribute.Exceptions); |
jjg@46 | 456 | if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions |
jjg@46 | 457 | if (e_attr instanceof Exceptions_attribute) { |
jjg@46 | 458 | Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; |
jjg@46 | 459 | print(" throws "); |
jjg@46 | 460 | if (methodExceptions != null) { // use generic list if available |
jjg@46 | 461 | writeList("", methodExceptions, ""); |
jjg@46 | 462 | } else { |
jjg@46 | 463 | for (int i = 0; i < exceptions.number_of_exceptions; i++) { |
jjg@46 | 464 | if (i > 0) |
jjg@46 | 465 | print(", "); |
jjg@52 | 466 | print(getJavaException(exceptions, i)); |
jjg@46 | 467 | } |
jjg@46 | 468 | } |
jjg@46 | 469 | } else { |
jjg@46 | 470 | report("Unexpected or invalid value for Exceptions attribute"); |
jjg@46 | 471 | } |
jjg@46 | 472 | } |
jjg@46 | 473 | |
jjg@348 | 474 | println(";"); |
jjg@46 | 475 | |
jjg@348 | 476 | indent(+1); |
jjg@46 | 477 | |
jjg@1578 | 478 | if (options.showDescriptors) { |
jjg@1578 | 479 | println("descriptor: " + getValue(m.descriptor)); |
jjg@348 | 480 | } |
jjg@348 | 481 | |
jjg@348 | 482 | if (options.verbose && !options.compat) { |
jjh@1478 | 483 | writeList("flags: ", flags.getMethodFlags(), "\n"); |
jjg@348 | 484 | } |
jjg@46 | 485 | |
jjg@46 | 486 | Code_attribute code = null; |
jjg@46 | 487 | Attribute c_attr = m.attributes.get(Attribute.Code); |
jjg@46 | 488 | if (c_attr != null) { |
jjg@46 | 489 | if (c_attr instanceof Code_attribute) |
jjg@46 | 490 | code = (Code_attribute) c_attr; |
jjg@46 | 491 | else |
jjg@46 | 492 | report("Unexpected or invalid value for Code attribute"); |
jjg@46 | 493 | } |
jjg@46 | 494 | |
jjg@46 | 495 | if (options.showDisassembled && !options.showAllAttrs) { |
jjg@46 | 496 | if (code != null) { |
jjg@348 | 497 | println("Code:"); |
jjg@46 | 498 | codeWriter.writeInstrs(code); |
jjg@46 | 499 | codeWriter.writeExceptionTable(code); |
jjg@46 | 500 | } |
jjg@46 | 501 | } |
jjg@46 | 502 | |
jjg@46 | 503 | if (options.showLineAndLocalVariableTables) { |
jjg@348 | 504 | if (code != null) { |
jjg@46 | 505 | attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool); |
jjg@46 | 506 | attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool); |
jjg@348 | 507 | } |
jjg@46 | 508 | } |
jjg@46 | 509 | |
jjg@46 | 510 | if (options.showAllAttrs) { |
jjg@46 | 511 | Attribute[] attrs = m.attributes.attrs; |
jjg@46 | 512 | for (Attribute attr: attrs) |
jjg@46 | 513 | attrWriter.write(m, attr, constant_pool); |
jjg@348 | 514 | } |
jjg@46 | 515 | |
jjg@348 | 516 | indent(-1); |
jjg@348 | 517 | |
jjg@348 | 518 | // set pendingNewline to write a newline before the next method (if any) |
jjg@348 | 519 | // if a separator is desired |
jjg@348 | 520 | setPendingNewline( |
jjg@348 | 521 | options.showDisassembled || |
jjg@348 | 522 | options.showAllAttrs || |
jjg@1578 | 523 | options.showDescriptors || |
jjg@348 | 524 | options.showLineAndLocalVariableTables || |
jjg@348 | 525 | options.verbose); |
jjg@46 | 526 | } |
jjg@46 | 527 | |
jjg@46 | 528 | void writeModifiers(Collection<String> items) { |
jjg@46 | 529 | for (Object item: items) { |
jjg@46 | 530 | print(item); |
jjg@46 | 531 | print(" "); |
jjg@46 | 532 | } |
jjg@46 | 533 | } |
jjg@46 | 534 | |
jjg@46 | 535 | void writeList(String prefix, Collection<?> items, String suffix) { |
jjg@46 | 536 | print(prefix); |
jjg@46 | 537 | String sep = ""; |
jjg@46 | 538 | for (Object item: items) { |
jjg@46 | 539 | print(sep); |
jjg@46 | 540 | print(item); |
jjg@46 | 541 | sep = ", "; |
jjg@46 | 542 | } |
jjg@46 | 543 | print(suffix); |
jjg@46 | 544 | } |
jjg@46 | 545 | |
jjg@46 | 546 | void writeListIfNotEmpty(String prefix, List<?> items, String suffix) { |
jjg@46 | 547 | if (items != null && items.size() > 0) |
jjg@46 | 548 | writeList(prefix, items, suffix); |
jjg@46 | 549 | } |
jjg@46 | 550 | |
jjg@46 | 551 | Signature_attribute getSignature(Attributes attributes) { |
jjg@46 | 552 | if (options.compat) // javap does not recognize recent attributes |
jjg@46 | 553 | return null; |
jjg@46 | 554 | return (Signature_attribute) attributes.get(Attribute.Signature); |
jjg@46 | 555 | } |
jjg@46 | 556 | |
jjg@46 | 557 | String adjustVarargs(AccessFlags flags, String params) { |
jjg@46 | 558 | if (flags.is(ACC_VARARGS) && !options.compat) { |
jjg@46 | 559 | int i = params.lastIndexOf("[]"); |
jjg@46 | 560 | if (i > 0) |
jjg@46 | 561 | return params.substring(0, i) + "..." + params.substring(i+2); |
jjg@46 | 562 | } |
jjg@46 | 563 | |
jjg@46 | 564 | return params; |
jjg@46 | 565 | } |
jjg@46 | 566 | |
jjg@46 | 567 | String getJavaName(ClassFile cf) { |
jjg@46 | 568 | try { |
jjg@46 | 569 | return getJavaName(cf.getName()); |
jjg@46 | 570 | } catch (ConstantPoolException e) { |
jjg@46 | 571 | return report(e); |
jjg@46 | 572 | } |
jjg@46 | 573 | } |
jjg@46 | 574 | |
jjg@46 | 575 | String getJavaSuperclassName(ClassFile cf) { |
jjg@46 | 576 | try { |
jjg@46 | 577 | return getJavaName(cf.getSuperclassName()); |
jjg@46 | 578 | } catch (ConstantPoolException e) { |
jjg@46 | 579 | return report(e); |
jjg@46 | 580 | } |
jjg@46 | 581 | } |
jjg@46 | 582 | |
jjg@46 | 583 | String getJavaInterfaceName(ClassFile cf, int index) { |
jjg@46 | 584 | try { |
jjg@46 | 585 | return getJavaName(cf.getInterfaceName(index)); |
jjg@46 | 586 | } catch (ConstantPoolException e) { |
jjg@46 | 587 | return report(e); |
jjg@46 | 588 | } |
jjg@46 | 589 | } |
jjg@46 | 590 | |
jjg@528 | 591 | String getJavaFieldType(Descriptor d) { |
jjg@46 | 592 | try { |
jjg@528 | 593 | return getJavaName(d.getFieldType(constant_pool)); |
jjg@46 | 594 | } catch (ConstantPoolException e) { |
jjg@46 | 595 | return report(e); |
jjg@46 | 596 | } catch (DescriptorException e) { |
jjg@46 | 597 | return report(e); |
jjg@46 | 598 | } |
jjg@46 | 599 | } |
jjg@46 | 600 | |
jjg@528 | 601 | String getJavaReturnType(Descriptor d) { |
jjg@46 | 602 | try { |
jjg@528 | 603 | return getJavaName(d.getReturnType(constant_pool)); |
jjg@46 | 604 | } catch (ConstantPoolException e) { |
jjg@46 | 605 | return report(e); |
jjg@46 | 606 | } catch (DescriptorException e) { |
jjg@46 | 607 | return report(e); |
jjg@46 | 608 | } |
jjg@46 | 609 | } |
jjg@46 | 610 | |
jjg@528 | 611 | String getJavaParameterTypes(Descriptor d, AccessFlags flags) { |
jjg@46 | 612 | try { |
jjg@528 | 613 | return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool))); |
jjg@46 | 614 | } catch (ConstantPoolException e) { |
jjg@46 | 615 | return report(e); |
jjg@46 | 616 | } catch (DescriptorException e) { |
jjg@46 | 617 | return report(e); |
jjg@46 | 618 | } |
jjg@46 | 619 | } |
jjg@46 | 620 | |
jjg@52 | 621 | String getJavaException(Exceptions_attribute attr, int index) { |
jjg@52 | 622 | try { |
jjg@52 | 623 | return getJavaName(attr.getException(index, constant_pool)); |
jjg@52 | 624 | } catch (ConstantPoolException e) { |
jjg@52 | 625 | return report(e); |
jjg@52 | 626 | } |
jjg@52 | 627 | } |
jjg@52 | 628 | |
jjg@46 | 629 | String getValue(Descriptor d) { |
jjg@46 | 630 | try { |
jjg@46 | 631 | return d.getValue(constant_pool); |
jjg@46 | 632 | } catch (ConstantPoolException e) { |
jjg@46 | 633 | return report(e); |
jjg@46 | 634 | } |
jjg@46 | 635 | } |
jjg@46 | 636 | |
jjg@46 | 637 | String getFieldName(Field f) { |
jjg@46 | 638 | try { |
jjg@46 | 639 | return f.getName(constant_pool); |
jjg@46 | 640 | } catch (ConstantPoolException e) { |
jjg@46 | 641 | return report(e); |
jjg@46 | 642 | } |
jjg@46 | 643 | } |
jjg@46 | 644 | |
jjg@46 | 645 | String getName(Method m) { |
jjg@46 | 646 | try { |
jjg@46 | 647 | return m.getName(constant_pool); |
jjg@46 | 648 | } catch (ConstantPoolException e) { |
jjg@46 | 649 | return report(e); |
jjg@46 | 650 | } |
jjg@46 | 651 | } |
jjg@46 | 652 | |
jjg@46 | 653 | static String getJavaName(String name) { |
jjg@46 | 654 | return name.replace('/', '.'); |
jjg@46 | 655 | } |
jjg@46 | 656 | |
jjg@46 | 657 | String getSourceFile(SourceFile_attribute attr) { |
jjg@46 | 658 | try { |
jjg@46 | 659 | return attr.getSourceFile(constant_pool); |
jjg@46 | 660 | } catch (ConstantPoolException e) { |
jjg@46 | 661 | return report(e); |
jjg@46 | 662 | } |
jjg@46 | 663 | } |
jjg@46 | 664 | |
jjg@87 | 665 | /** |
jjg@87 | 666 | * Get the value of an entry in the constant pool as a Java constant. |
jjg@87 | 667 | * Characters and booleans are represented by CONSTANT_Intgere entries. |
jjg@87 | 668 | * Character and string values are processed to escape characters outside |
jjg@87 | 669 | * the basic printable ASCII set. |
jjg@87 | 670 | * @param d the descriptor, giving the expected type of the constant |
jjg@87 | 671 | * @param index the index of the value in the constant pool |
jjg@87 | 672 | * @return a printable string containing the value of the constant. |
jjg@87 | 673 | */ |
jjg@87 | 674 | String getConstantValue(Descriptor d, int index) { |
jjg@87 | 675 | try { |
jjg@87 | 676 | ConstantPool.CPInfo cpInfo = constant_pool.get(index); |
jjg@87 | 677 | |
jjg@87 | 678 | switch (cpInfo.getTag()) { |
jjg@87 | 679 | case ConstantPool.CONSTANT_Integer: { |
jjg@87 | 680 | ConstantPool.CONSTANT_Integer_info info = |
jjg@87 | 681 | (ConstantPool.CONSTANT_Integer_info) cpInfo; |
jjg@87 | 682 | String t = d.getValue(constant_pool); |
jjg@87 | 683 | if (t.equals("C")) { // character |
jjg@87 | 684 | return getConstantCharValue((char) info.value); |
jjg@87 | 685 | } else if (t.equals("Z")) { // boolean |
jjg@87 | 686 | return String.valueOf(info.value == 1); |
jjg@87 | 687 | } else { // other: assume integer |
jjg@87 | 688 | return String.valueOf(info.value); |
jjg@87 | 689 | } |
jjg@87 | 690 | } |
jjg@87 | 691 | |
jjg@87 | 692 | case ConstantPool.CONSTANT_String: { |
jjg@87 | 693 | ConstantPool.CONSTANT_String_info info = |
jjg@87 | 694 | (ConstantPool.CONSTANT_String_info) cpInfo; |
jjg@87 | 695 | return getConstantStringValue(info.getString()); |
jjg@87 | 696 | } |
jjg@87 | 697 | |
jjg@87 | 698 | default: |
jjg@87 | 699 | return constantWriter.stringValue(cpInfo); |
jjg@87 | 700 | } |
jjg@87 | 701 | } catch (ConstantPoolException e) { |
jjg@87 | 702 | return "#" + index; |
jjg@87 | 703 | } |
jjg@87 | 704 | } |
jjg@87 | 705 | |
jjg@87 | 706 | private String getConstantCharValue(char c) { |
jjg@87 | 707 | StringBuilder sb = new StringBuilder(); |
jjg@87 | 708 | sb.append('\''); |
jjg@87 | 709 | sb.append(esc(c, '\'')); |
jjg@87 | 710 | sb.append('\''); |
jjg@87 | 711 | return sb.toString(); |
jjg@87 | 712 | } |
jjg@87 | 713 | |
jjg@87 | 714 | private String getConstantStringValue(String s) { |
jjg@87 | 715 | StringBuilder sb = new StringBuilder(); |
jjg@87 | 716 | sb.append("\""); |
jjg@87 | 717 | for (int i = 0; i < s.length(); i++) { |
jjg@87 | 718 | sb.append(esc(s.charAt(i), '"')); |
jjg@87 | 719 | } |
jjg@87 | 720 | sb.append("\""); |
jjg@87 | 721 | return sb.toString(); |
jjg@87 | 722 | } |
jjg@87 | 723 | |
jjg@87 | 724 | private String esc(char c, char quote) { |
jjg@87 | 725 | if (32 <= c && c <= 126 && c != quote) |
jjg@87 | 726 | return String.valueOf(c); |
jjg@87 | 727 | else switch (c) { |
jjg@87 | 728 | case '\b': return "\\b"; |
jjg@87 | 729 | case '\n': return "\\n"; |
jjg@87 | 730 | case '\t': return "\\t"; |
jjg@87 | 731 | case '\f': return "\\f"; |
jjg@87 | 732 | case '\r': return "\\r"; |
jjg@87 | 733 | case '\\': return "\\\\"; |
jjg@87 | 734 | case '\'': return "\\'"; |
jjg@87 | 735 | case '\"': return "\\\""; |
jjg@87 | 736 | default: return String.format("\\u%04x", (int) c); |
jjg@87 | 737 | } |
jjg@87 | 738 | } |
jjg@87 | 739 | |
jjg@46 | 740 | private Options options; |
jjg@46 | 741 | private AttributeWriter attrWriter; |
jjg@46 | 742 | private CodeWriter codeWriter; |
jjg@46 | 743 | private ConstantWriter constantWriter; |
jjg@46 | 744 | private ClassFile classFile; |
jjg@88 | 745 | private URI uri; |
jjg@88 | 746 | private long lastModified; |
jjg@88 | 747 | private String digestName; |
jjg@88 | 748 | private byte[] digest; |
jjg@88 | 749 | private int size; |
jjg@46 | 750 | private ConstantPool constant_pool; |
jjg@46 | 751 | private Method method; |
jjg@46 | 752 | } |