1 /******************************************************************************* 2 * Copyright (c) 2009, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.equinox.p2.internal.repository.comparator.java; 15 16 import java.util.Arrays; 17 import org.eclipse.osgi.util.NLS; 18 19 /** 20 * Disassembler of .class files. It generates an output in the Writer that looks close to 21 * the javap output. 22 */ 23 public class Disassembler { 24 /** 25 * The mode is the detailed mode to disassemble ClassFileReader. It returns the magic 26 * numbers, the version numbers and field and method descriptors. 27 */ 28 public final static int DETAILED = 1; 29 30 /** 31 * This mode is used to compact the class name to a simple name instead of a qualified name. 32 * @since 3.1 33 */ 34 public final static int COMPACT = 8; 35 36 private static final char[] ANY_EXCEPTION = Messages.classfileformat_anyexceptionhandler.toCharArray(); 37 private static final String VERSION_UNKNOWN = Messages.classfileformat_versionUnknown; 38 appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier)39 private boolean appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier) { 40 if ((accessFlags & modifierConstant) != 0) { 41 if (!firstModifier) { 42 buffer.append(Messages.disassembler_space); 43 } 44 if (firstModifier) { 45 firstModifier = false; 46 } 47 buffer.append(modifier); 48 } 49 return firstModifier; 50 } 51 decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits)52 private void decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits) { 53 decodeModifiers(buffer, accessFlags, false, false, checkBits); 54 } 55 decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits)56 private void decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits) { 57 if (checkBits == null) 58 return; 59 boolean firstModifier = true; 60 for (int checkBit : checkBits) { 61 switch (checkBit) { 62 case IModifierConstants.ACC_PUBLIC : 63 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$ 64 break; 65 case IModifierConstants.ACC_PROTECTED : 66 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$ 67 break; 68 case IModifierConstants.ACC_PRIVATE : 69 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$ 70 break; 71 case IModifierConstants.ACC_ABSTRACT : 72 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$ 73 break; 74 case IModifierConstants.ACC_STATIC : 75 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$ 76 break; 77 case IModifierConstants.ACC_FINAL : 78 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$ 79 break; 80 case IModifierConstants.ACC_SYNCHRONIZED : 81 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$ 82 break; 83 case IModifierConstants.ACC_NATIVE : 84 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$ 85 break; 86 case IModifierConstants.ACC_STRICT : 87 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$ 88 break; 89 case IModifierConstants.ACC_TRANSIENT : 90 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$ 91 break; 92 case IModifierConstants.ACC_VOLATILE : 93 // case IModifierConstants.ACC_BRIDGE : 94 if (asBridge) { 95 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$ 96 } else { 97 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$ 98 } 99 break; 100 case IModifierConstants.ACC_ENUM : 101 firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$ 102 break; 103 } 104 } 105 if (!firstModifier) { 106 if (!printDefault) 107 buffer.append(Messages.disassembler_space); 108 } else if (printDefault) { 109 // no modifier: package default visibility 110 buffer.append("default"); //$NON-NLS-1$ 111 } 112 } 113 decodeModifiersForField(StringBuffer buffer, int accessFlags)114 private void decodeModifiersForField(StringBuffer buffer, int accessFlags) { 115 decodeModifiers(buffer, accessFlags, new int[] {IModifierConstants.ACC_PUBLIC, IModifierConstants.ACC_PROTECTED, IModifierConstants.ACC_PRIVATE, IModifierConstants.ACC_STATIC, IModifierConstants.ACC_FINAL, IModifierConstants.ACC_TRANSIENT, IModifierConstants.ACC_VOLATILE, IModifierConstants.ACC_ENUM}); 116 } 117 decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault)118 private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault) { 119 decodeModifiers(buffer, accessFlags, printDefault, false, new int[] {IModifierConstants.ACC_PUBLIC, IModifierConstants.ACC_PROTECTED, IModifierConstants.ACC_PRIVATE, IModifierConstants.ACC_ABSTRACT, IModifierConstants.ACC_STATIC, IModifierConstants.ACC_FINAL,}); 120 } 121 decodeModifiersForMethod(StringBuffer buffer, int accessFlags)122 private final void decodeModifiersForMethod(StringBuffer buffer, int accessFlags) { 123 decodeModifiers(buffer, accessFlags, false, true, new int[] {IModifierConstants.ACC_PUBLIC, IModifierConstants.ACC_PROTECTED, IModifierConstants.ACC_PRIVATE, IModifierConstants.ACC_ABSTRACT, IModifierConstants.ACC_STATIC, IModifierConstants.ACC_FINAL, IModifierConstants.ACC_SYNCHRONIZED, IModifierConstants.ACC_NATIVE, IModifierConstants.ACC_STRICT, IModifierConstants.ACC_BRIDGE,}); 124 } 125 decodeModifiersForType(StringBuffer buffer, int accessFlags)126 private final void decodeModifiersForType(StringBuffer buffer, int accessFlags) { 127 decodeModifiers(buffer, accessFlags, new int[] {IModifierConstants.ACC_PUBLIC, IModifierConstants.ACC_ABSTRACT, IModifierConstants.ACC_FINAL,}); 128 } 129 escapeString(String s)130 public static String escapeString(String s) { 131 StringBuilder buffer = new StringBuilder(); 132 for (int i = 0, max = s.length(); i < max; i++) { 133 char c = s.charAt(i); 134 switch (c) { 135 case '\b' : 136 buffer.append("\\b"); //$NON-NLS-1$ 137 break; 138 case '\t' : 139 buffer.append("\\t"); //$NON-NLS-1$ 140 break; 141 case '\n' : 142 buffer.append("\\n"); //$NON-NLS-1$ 143 break; 144 case '\f' : 145 buffer.append("\\f"); //$NON-NLS-1$ 146 break; 147 case '\r' : 148 buffer.append("\\r"); //$NON-NLS-1$ 149 break; 150 case '\0' : 151 buffer.append("\\0"); //$NON-NLS-1$ 152 break; 153 case '\1' : 154 buffer.append("\\1"); //$NON-NLS-1$ 155 break; 156 case '\2' : 157 buffer.append("\\2"); //$NON-NLS-1$ 158 break; 159 case '\3' : 160 buffer.append("\\3"); //$NON-NLS-1$ 161 break; 162 case '\4' : 163 buffer.append("\\4"); //$NON-NLS-1$ 164 break; 165 case '\5' : 166 buffer.append("\\5"); //$NON-NLS-1$ 167 break; 168 case '\6' : 169 buffer.append("\\6"); //$NON-NLS-1$ 170 break; 171 case '\7' : 172 buffer.append("\\7"); //$NON-NLS-1$ 173 break; 174 default : 175 buffer.append(c); 176 } 177 } 178 return buffer.toString(); 179 } 180 decodeStringValue(char[] chars)181 static String decodeStringValue(char[] chars) { 182 StringBuilder buffer = new StringBuilder(); 183 for (char c : chars) { 184 switch (c) { 185 case '\b' : 186 buffer.append("\\b"); //$NON-NLS-1$ 187 break; 188 case '\t' : 189 buffer.append("\\t"); //$NON-NLS-1$ 190 break; 191 case '\n' : 192 buffer.append("\\n"); //$NON-NLS-1$ 193 break; 194 case '\f' : 195 buffer.append("\\f"); //$NON-NLS-1$ 196 break; 197 case '\r' : 198 buffer.append("\\r"); //$NON-NLS-1$ 199 break; 200 case '\0' : 201 buffer.append("\\0"); //$NON-NLS-1$ 202 break; 203 case '\1' : 204 buffer.append("\\1"); //$NON-NLS-1$ 205 break; 206 case '\2' : 207 buffer.append("\\2"); //$NON-NLS-1$ 208 break; 209 case '\3' : 210 buffer.append("\\3"); //$NON-NLS-1$ 211 break; 212 case '\4' : 213 buffer.append("\\4"); //$NON-NLS-1$ 214 break; 215 case '\5' : 216 buffer.append("\\5"); //$NON-NLS-1$ 217 break; 218 case '\6' : 219 buffer.append("\\6"); //$NON-NLS-1$ 220 break; 221 case '\7' : 222 buffer.append("\\7"); //$NON-NLS-1$ 223 break; 224 default : 225 buffer.append(c); 226 } 227 } 228 return buffer.toString(); 229 } 230 decodeStringValue(String s)231 static String decodeStringValue(String s) { 232 return decodeStringValue(s.toCharArray()); 233 } 234 235 /* 236 * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int) 237 */ disassemble(byte[] classFileBytes, String lineSeparator, int mode)238 public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException { 239 try { 240 return disassemble(new ClassFileReader(classFileBytes, ClassFileReader.ALL), lineSeparator, mode); 241 } catch (ArrayIndexOutOfBoundsException e) { 242 throw new ClassFormatException(e.getMessage(), e); 243 } 244 } 245 disassemble(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)246 private void disassemble(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 247 writeNewLine(buffer, lineSeparator, tabNumber + 1); 248 final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.'); 249 buffer.append(NLS.bind(Messages.disassembler_annotationentrystart, new String[] {new String(returnClassName(Signature.toCharArray(typeName), '.', mode))})); 250 for (AnnotationComponent component : annotation.getComponents()) { 251 disassemble(component, buffer, lineSeparator, tabNumber + 1, mode); 252 } 253 writeNewLine(buffer, lineSeparator, tabNumber + 1); 254 buffer.append(Messages.disassembler_annotationentryend); 255 } 256 disassemble(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)257 private void disassemble(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 258 writeNewLine(buffer, lineSeparator, tabNumber + 1); 259 buffer.append(NLS.bind(Messages.disassembler_annotationcomponent, new String[] {new String(annotationComponent.getComponentName())})); 260 disassemble(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode); 261 } 262 disassemble(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)263 private void disassemble(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 264 switch (annotationComponentValue.getTag()) { 265 case AnnotationComponentValue.BYTE_TAG : 266 case AnnotationComponentValue.CHAR_TAG : 267 case AnnotationComponentValue.DOUBLE_TAG : 268 case AnnotationComponentValue.FLOAT_TAG : 269 case AnnotationComponentValue.INTEGER_TAG : 270 case AnnotationComponentValue.LONG_TAG : 271 case AnnotationComponentValue.SHORT_TAG : 272 case AnnotationComponentValue.BOOLEAN_TAG : 273 case AnnotationComponentValue.STRING_TAG : 274 ConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue(); 275 String value = null; 276 switch (constantPoolEntry.getKind()) { 277 case ConstantPoolConstant.CONSTANT_Long : 278 value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$ 279 break; 280 case ConstantPoolConstant.CONSTANT_Float : 281 value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$ 282 break; 283 case ConstantPoolConstant.CONSTANT_Double : 284 value = Double.toString(constantPoolEntry.getDoubleValue()); 285 break; 286 case ConstantPoolConstant.CONSTANT_Integer : 287 switch (annotationComponentValue.getTag()) { 288 case AnnotationComponentValue.CHAR_TAG : 289 value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$ 290 break; 291 case AnnotationComponentValue.BOOLEAN_TAG : 292 value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$ 293 break; 294 case AnnotationComponentValue.BYTE_TAG : 295 value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 296 break; 297 case AnnotationComponentValue.SHORT_TAG : 298 value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 299 break; 300 case AnnotationComponentValue.INTEGER_TAG : 301 value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 302 } 303 break; 304 case ConstantPoolConstant.CONSTANT_Utf8 : 305 value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$ 306 } 307 buffer.append(NLS.bind(Messages.disassembler_annotationdefaultvalue, value)); 308 break; 309 case AnnotationComponentValue.ENUM_TAG : 310 final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.'); 311 final char[] constantName = annotationComponentValue.getEnumConstantName(); 312 buffer.append(NLS.bind(Messages.disassembler_annotationenumvalue, new String[] {new String(returnClassName(Signature.toCharArray(typeName), '.', mode)), new String(constantName)})); 313 break; 314 case AnnotationComponentValue.CLASS_TAG : 315 constantPoolEntry = annotationComponentValue.getClassInfo(); 316 final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.'); 317 buffer.append(NLS.bind(Messages.disassembler_annotationclassvalue, new String[] {new String(returnClassName(Signature.toCharArray(className), '.', mode))})); 318 break; 319 case AnnotationComponentValue.ANNOTATION_TAG : 320 buffer.append(Messages.disassembler_annotationannotationvalue); 321 Annotation annotation = annotationComponentValue.getAnnotationValue(); 322 disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode); 323 break; 324 case AnnotationComponentValue.ARRAY_TAG: 325 buffer.append(Messages.disassembler_annotationarrayvaluestart); 326 final AnnotationComponentValue[] annotationComponentValues = annotationComponentValue 327 .getAnnotationComponentValues(); 328 for (AnnotationComponentValue annotationComponentValue2 : annotationComponentValues) { 329 writeNewLine(buffer, lineSeparator, tabNumber + 1); 330 disassemble(annotationComponentValue2, buffer, lineSeparator, tabNumber + 1, mode); 331 } 332 writeNewLine(buffer, lineSeparator, tabNumber + 1); 333 buffer.append(Messages.disassembler_annotationarrayvalueend); 334 } 335 } 336 disassemble(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)337 private void disassemble(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 338 writeNewLine(buffer, lineSeparator, tabNumber + 1); 339 buffer.append(Messages.disassembler_annotationdefaultheader); 340 AnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue(); 341 writeNewLine(buffer, lineSeparator, tabNumber + 2); 342 disassemble(componentValue, buffer, lineSeparator, tabNumber + 1, mode); 343 } 344 345 /** 346 * Disassemble a method info header 347 */ disassemble(ClassFileReader classFileReader, char[] className, MethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)348 private void disassemble(ClassFileReader classFileReader, char[] className, MethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 349 writeNewLine(buffer, lineSeparator, tabNumber); 350 final CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); 351 final char[] methodDescriptor = methodInfo.getDescriptor(); 352 final SignatureAttribute signatureAttribute = (SignatureAttribute) Utility.getAttribute(methodInfo, AttributeNamesConstants.SIGNATURE); 353 final ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); 354 final ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); 355 final ClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); 356 final ClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); 357 final ClassFileAttribute annotationDefaultAttribute = Utility.getAttribute(methodInfo, AttributeNamesConstants.ANNOTATION_DEFAULT); 358 if (checkMode(mode, DETAILED)) { 359 buffer.append(NLS.bind(Messages.classfileformat_methoddescriptor, new String[] {new String(methodDescriptor)})); 360 if (methodInfo.isDeprecated()) { 361 buffer.append(Messages.disassembler_deprecated); 362 } 363 writeNewLine(buffer, lineSeparator, tabNumber); 364 if (signatureAttribute != null) { 365 buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); 366 writeNewLine(buffer, lineSeparator, tabNumber); 367 } 368 if (codeAttribute != null) { 369 buffer.append(NLS.bind(Messages.classfileformat_stacksAndLocals, new String[] {Integer.toString(codeAttribute.getMaxStack()), Integer.toString(codeAttribute.getMaxLocals())})); 370 writeNewLine(buffer, lineSeparator, tabNumber); 371 } 372 // disassemble compact version of annotations 373 if (runtimeInvisibleAnnotationsAttribute != null) { 374 disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 375 writeNewLine(buffer, lineSeparator, tabNumber); 376 } 377 if (runtimeVisibleAnnotationsAttribute != null) { 378 disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 379 writeNewLine(buffer, lineSeparator, tabNumber); 380 } 381 } 382 final int accessFlags = methodInfo.getAccessFlags(); 383 decodeModifiersForMethod(buffer, accessFlags); 384 if (methodInfo.isSynthetic()) { 385 buffer.append("synthetic"); //$NON-NLS-1$ 386 buffer.append(Messages.disassembler_space); 387 } 388 CharOperation.replace(methodDescriptor, '/', '.'); 389 final boolean isVarArgs = isVarArgs(methodInfo); 390 char[] methodHeader = null; 391 if (methodInfo.isConstructor()) { 392 methodHeader = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), null, !checkMode(mode, COMPACT), false, isVarArgs); 393 } else if (methodInfo.isClinit()) { 394 methodHeader = Messages.classfileformat_clinitname.toCharArray(); 395 } else { 396 methodHeader = Signature.toCharArray(methodDescriptor, methodInfo.getName(), null, !checkMode(mode, COMPACT), true, isVarArgs); 397 } 398 if (checkMode(mode, DETAILED) && (runtimeInvisibleParameterAnnotationsAttribute != null || runtimeVisibleParameterAnnotationsAttribute != null)) { 399 ParameterAnnotation[] invisibleParameterAnnotations = null; 400 ParameterAnnotation[] visibleParameterAnnotations = null; 401 int length = -1; 402 if (runtimeInvisibleParameterAnnotationsAttribute != null) { 403 RuntimeInvisibleParameterAnnotationsAttribute attribute = (RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute; 404 invisibleParameterAnnotations = attribute.getParameterAnnotations(); 405 length = invisibleParameterAnnotations.length; 406 } 407 if (runtimeVisibleParameterAnnotationsAttribute != null) { 408 RuntimeVisibleParameterAnnotationsAttribute attribute = (RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute; 409 visibleParameterAnnotations = attribute.getParameterAnnotations(); 410 length = visibleParameterAnnotations.length; 411 } 412 int insertionPosition = CharOperation.indexOf('(', methodHeader) + 1; 413 int start = 0; 414 StringBuffer stringBuffer = new StringBuffer(); 415 stringBuffer.append(methodHeader, 0, insertionPosition); 416 for (int i = 0; i < length; i++) { 417 if (i > 0) { 418 stringBuffer.append(' '); 419 } 420 int stringBufferSize = stringBuffer.length(); 421 if (runtimeVisibleParameterAnnotationsAttribute != null) { 422 disassembleAsModifier((RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, stringBuffer, i, lineSeparator, tabNumber, mode); 423 } 424 if (runtimeInvisibleParameterAnnotationsAttribute != null) { 425 if (stringBuffer.length() != stringBufferSize) { 426 stringBuffer.append(' '); 427 stringBufferSize = stringBuffer.length(); 428 } 429 disassembleAsModifier((RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, stringBuffer, i, lineSeparator, tabNumber, mode); 430 } 431 if (i == 0 && stringBuffer.length() != stringBufferSize) { 432 stringBuffer.append(' '); 433 } 434 start = insertionPosition; 435 insertionPosition = CharOperation.indexOf(',', methodHeader, start + 1) + 1; 436 if (insertionPosition == 0) { 437 stringBuffer.append(methodHeader, start, methodHeader.length - start); 438 } else { 439 stringBuffer.append(methodHeader, start, insertionPosition - start); 440 } 441 } 442 buffer.append(stringBuffer); 443 } else { 444 buffer.append(methodHeader); 445 } 446 ExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute(); 447 if (exceptionAttribute != null) { 448 buffer.append(" throws "); //$NON-NLS-1$ 449 char[][] exceptionNames = exceptionAttribute.getExceptionNames(); 450 int length = exceptionNames.length; 451 for (int i = 0; i < length; i++) { 452 if (i != 0) { 453 buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space); 454 } 455 char[] exceptionName = exceptionNames[i]; 456 CharOperation.replace(exceptionName, '/', '.'); 457 buffer.append(returnClassName(exceptionName, '.', mode)); 458 } 459 } 460 if (checkMode(mode, DETAILED)) { 461 if (annotationDefaultAttribute != null) { 462 buffer.append(" default "); //$NON-NLS-1$ 463 disassembleAsModifier((AnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode); 464 } 465 } 466 buffer.append(Messages.disassembler_endofmethodheader); 467 468 if (checkMode(mode, DETAILED)) { 469 if (codeAttribute != null) { 470 disassemble(codeAttribute, methodDescriptor, (accessFlags & IModifierConstants.ACC_STATIC) != 0, buffer, lineSeparator, tabNumber, mode); 471 } 472 if (annotationDefaultAttribute != null) { 473 disassemble((AnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode); 474 } 475 if (runtimeVisibleAnnotationsAttribute != null) { 476 disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 477 } 478 if (runtimeInvisibleAnnotationsAttribute != null) { 479 disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 480 } 481 if (runtimeVisibleParameterAnnotationsAttribute != null) { 482 disassemble((RuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 483 } 484 if (runtimeInvisibleParameterAnnotationsAttribute != null) { 485 disassemble((RuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 486 } 487 } 488 } 489 490 /** 491 * Answers back the disassembled string of the ClassFileReader according to the 492 * mode. 493 * This is an output quite similar to the javap tool. 494 * 495 * @param classFileReader The classFileReader to be disassembled 496 * @param lineSeparator the line separator to use. 497 * @param mode the mode used to disassemble the ClassFileReader 498 * 499 * @return the disassembled string of the ClassFileReader according to the mode 500 */ disassemble(ClassFileReader classFileReader, String lineSeparator, int mode)501 private String disassemble(ClassFileReader classFileReader, String lineSeparator, int mode) { 502 if (classFileReader == null) 503 return Utility.EMPTY_STRING; 504 char[] className = classFileReader.getClassName(); 505 if (className == null) { 506 // incomplete initialization. We cannot go further. 507 return Utility.EMPTY_STRING; 508 } 509 className = CharOperation.replaceOnCopy(className, '/', '.'); 510 final int accessFlags = classFileReader.getAccessFlags(); 511 final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0; 512 513 StringBuffer buffer = new StringBuffer(); 514 SourceFileAttribute sourceAttribute = classFileReader.getSourceFileAttribute(); 515 ClassFileAttribute classFileAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.SIGNATURE); 516 SignatureAttribute signatureAttribute = (SignatureAttribute) classFileAttribute; 517 if (checkMode(mode, DETAILED)) { 518 int minorVersion = classFileReader.getMinorVersion(); 519 int majorVersion = classFileReader.getMajorVersion(); 520 buffer.append(Messages.disassembler_begincommentline); 521 if (sourceAttribute != null) { 522 buffer.append(Messages.disassembler_sourceattributeheader); 523 buffer.append(sourceAttribute.getSourceFileName()); 524 } 525 String versionNumber = VERSION_UNKNOWN; 526 if (minorVersion == 3 && majorVersion == 45) { 527 versionNumber = IModifierConstants.VERSION_1_1; 528 } else if (minorVersion == 0 && majorVersion == 46) { 529 versionNumber = IModifierConstants.VERSION_1_2; 530 } else if (minorVersion == 0 && majorVersion == 47) { 531 versionNumber = IModifierConstants.VERSION_1_3; 532 } else if (minorVersion == 0 && majorVersion == 48) { 533 versionNumber = IModifierConstants.VERSION_1_4; 534 } else if (minorVersion == 0 && majorVersion == 49) { 535 versionNumber = IModifierConstants.VERSION_1_5; 536 } else if (minorVersion == 0 && majorVersion == 50) { 537 versionNumber = IModifierConstants.VERSION_1_6; 538 } else if (minorVersion == 0 && majorVersion == 51) { 539 versionNumber = IModifierConstants.VERSION_1_7; 540 } 541 buffer.append(NLS.bind(Messages.classfileformat_versiondetails, new String[] {versionNumber, Integer.toString(majorVersion), Integer.toString(minorVersion), ((accessFlags & IModifierConstants.ACC_SUPER) != 0 ? Messages.classfileformat_superflagisset : Messages.classfileformat_superflagisnotset) + (isDeprecated(classFileReader) ? ", deprecated" : Utility.EMPTY_STRING)//$NON-NLS-1$ 542 })); 543 writeNewLine(buffer, lineSeparator, 0); 544 if (signatureAttribute != null) { 545 buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); 546 writeNewLine(buffer, lineSeparator, 0); 547 } 548 } 549 550 InnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute(); 551 ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); 552 ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(classFileReader, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); 553 554 if (checkMode(mode, DETAILED)) { 555 // disassemble compact version of annotations 556 if (runtimeInvisibleAnnotationsAttribute != null) { 557 disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); 558 writeNewLine(buffer, lineSeparator, 0); 559 } 560 if (runtimeVisibleAnnotationsAttribute != null) { 561 disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); 562 writeNewLine(buffer, lineSeparator, 0); 563 } 564 } 565 boolean decoded = false; 566 if (innerClassesAttribute != null) { 567 // search the right entry 568 InnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries(); 569 for (InnerClassesAttributeEntry entry : entries) { 570 char[] innerClassName = entry.getInnerClassName(); 571 if (innerClassName != null) { 572 if (Arrays.equals(classFileReader.getClassName(), innerClassName)) { 573 decodeModifiersForInnerClasses(buffer, entry.getAccessFlags(), false); 574 decoded = true; 575 } 576 } 577 } 578 } 579 if (!decoded) { 580 decodeModifiersForType(buffer, accessFlags); 581 if (isSynthetic(classFileReader)) { 582 buffer.append("synthetic"); //$NON-NLS-1$ 583 buffer.append(Messages.disassembler_space); 584 } 585 } 586 587 final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0; 588 boolean isInterface = false; 589 if (isEnum) { 590 buffer.append("enum "); //$NON-NLS-1$ 591 } else if (classFileReader.isClass()) { 592 buffer.append("class "); //$NON-NLS-1$ 593 } else { 594 if (isAnnotation) { 595 buffer.append("@"); //$NON-NLS-1$ 596 } 597 buffer.append("interface "); //$NON-NLS-1$ 598 isInterface = true; 599 } 600 601 buffer.append(className); 602 603 char[] superclassName = classFileReader.getSuperclassName(); 604 if (superclassName != null) { 605 CharOperation.replace(superclassName, '/', '.'); 606 if (!isJavaLangObject(superclassName) && !isEnum) { 607 buffer.append(" extends "); //$NON-NLS-1$ 608 buffer.append(returnClassName(superclassName, '.', mode)); 609 } 610 } 611 if (!isAnnotation) { 612 char[][] superclassInterfaces = classFileReader.getInterfaceNames(); 613 int length = superclassInterfaces.length; 614 if (length != 0) { 615 if (isInterface) { 616 buffer.append(" extends "); //$NON-NLS-1$ 617 } else { 618 buffer.append(" implements "); //$NON-NLS-1$ 619 } 620 for (int i = 0; i < length; i++) { 621 if (i != 0) { 622 buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space); 623 } 624 char[] superinterface = superclassInterfaces[i]; 625 CharOperation.replace(superinterface, '/', '.'); 626 buffer.append(returnClassName(superinterface, '.', mode)); 627 } 628 } 629 } 630 buffer.append(Messages.disassembler_opentypedeclaration); 631 disassembleTypeMembers(classFileReader, className, buffer, lineSeparator, 1, mode, isEnum); 632 if (checkMode(mode, DETAILED)) { 633 ClassFileAttribute[] attributes = classFileReader.getAttributes(); 634 int length = attributes.length; 635 EnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader); 636 int remainingAttributesLength = length; 637 if (innerClassesAttribute != null) { 638 remainingAttributesLength--; 639 } 640 if (enclosingMethodAttribute != null) { 641 remainingAttributesLength--; 642 } 643 if (sourceAttribute != null) { 644 remainingAttributesLength--; 645 } 646 if (signatureAttribute != null) { 647 remainingAttributesLength--; 648 } 649 if (innerClassesAttribute != null || enclosingMethodAttribute != null || remainingAttributesLength != 0) { 650 writeNewLine(buffer, lineSeparator, 0); 651 } 652 if (innerClassesAttribute != null) { 653 disassemble(innerClassesAttribute, buffer, lineSeparator, 1); 654 } 655 if (enclosingMethodAttribute != null) { 656 disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0); 657 } 658 if (runtimeVisibleAnnotationsAttribute != null) { 659 disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); 660 } 661 if (runtimeInvisibleAnnotationsAttribute != null) { 662 disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); 663 } 664 } 665 writeNewLine(buffer, lineSeparator, 0); 666 buffer.append(Messages.disassembler_closetypedeclaration); 667 return buffer.toString(); 668 } 669 isJavaLangObject(final char[] className)670 private boolean isJavaLangObject(final char[] className) { 671 return Arrays.equals(TypeConstants.JAVA_LANG_OBJECT, CharOperation.splitOn('.', className)); 672 } 673 isVarArgs(MethodInfo methodInfo)674 private boolean isVarArgs(MethodInfo methodInfo) { 675 int accessFlags = methodInfo.getAccessFlags(); 676 if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0) 677 return true; 678 // check the presence of the unspecified Varargs attribute 679 return Utility.getAttribute(methodInfo, AttributeNamesConstants.VAR_ARGS) != null; 680 } 681 disassemble(CodeAttribute codeAttribute, char[] methodDescriptor, boolean isStatic, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)682 private void disassemble(CodeAttribute codeAttribute, char[] methodDescriptor, boolean isStatic, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 683 writeNewLine(buffer, lineSeparator, tabNumber - 1); 684 DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, methodDescriptor, isStatic, buffer, lineSeparator, tabNumber, mode); 685 try { 686 codeAttribute.traverse(visitor); 687 } catch (ClassFormatException e) { 688 dumpTab(tabNumber + 2, buffer); 689 buffer.append(Messages.classformat_classformatexception); 690 writeNewLine(buffer, lineSeparator, tabNumber + 1); 691 } 692 final int exceptionTableLength = codeAttribute.getExceptionTableLength(); 693 if (exceptionTableLength != 0) { 694 final int tabNumberForExceptionAttribute = tabNumber + 2; 695 dumpTab(tabNumberForExceptionAttribute, buffer); 696 final ExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable(); 697 buffer.append(Messages.disassembler_exceptiontableheader); 698 writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1); 699 for (int i = 0; i < exceptionTableLength; i++) { 700 if (i != 0) { 701 writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1); 702 } 703 ExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i]; 704 char[] catchType; 705 if (exceptionTableEntry.getCatchTypeIndex() != 0) { 706 catchType = exceptionTableEntry.getCatchType(); 707 CharOperation.replace(catchType, '/', '.'); 708 catchType = returnClassName(catchType, '.', mode); 709 } else { 710 catchType = ANY_EXCEPTION; 711 } 712 buffer.append(NLS.bind(Messages.classfileformat_exceptiontableentry, new String[] {Integer.toString(exceptionTableEntry.getStartPC()), Integer.toString(exceptionTableEntry.getEndPC()), Integer.toString(exceptionTableEntry.getHandlerPC()), new String(catchType),})); 713 } 714 } 715 } 716 disassemble(EnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber)717 private void disassemble(EnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { 718 writeNewLine(buffer, lineSeparator, tabNumber + 1); 719 buffer.append(Messages.disassembler_enclosingmethodheader); 720 buffer.append(" ")//$NON-NLS-1$ 721 .append(enclosingMethodAttribute.getEnclosingClass()); 722 if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) { 723 buffer.append(".")//$NON-NLS-1$ 724 .append(enclosingMethodAttribute.getMethodName()).append(enclosingMethodAttribute.getMethodDescriptor()); 725 } 726 } 727 728 /** 729 * Disassemble a field info 730 */ disassemble(FieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)731 private void disassemble(FieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 732 writeNewLine(buffer, lineSeparator, tabNumber); 733 final char[] fieldDescriptor = fieldInfo.getDescriptor(); 734 final SignatureAttribute signatureAttribute = (SignatureAttribute) Utility.getAttribute(fieldInfo, AttributeNamesConstants.SIGNATURE); 735 if (checkMode(mode, DETAILED)) { 736 buffer.append(NLS.bind(Messages.classfileformat_fieldddescriptor, new String[] {new String(fieldDescriptor)})); 737 if (fieldInfo.isDeprecated()) { 738 buffer.append(Messages.disassembler_deprecated); 739 } 740 writeNewLine(buffer, lineSeparator, tabNumber); 741 if (signatureAttribute != null) { 742 buffer.append(NLS.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); 743 writeNewLine(buffer, lineSeparator, tabNumber); 744 } 745 } 746 final ClassFileAttribute runtimeVisibleAnnotationsAttribute = Utility.getAttribute(fieldInfo, AttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); 747 final ClassFileAttribute runtimeInvisibleAnnotationsAttribute = Utility.getAttribute(fieldInfo, AttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); 748 if (checkMode(mode, DETAILED)) { 749 // disassemble compact version of annotations 750 if (runtimeInvisibleAnnotationsAttribute != null) { 751 disassembleAsModifier((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 752 writeNewLine(buffer, lineSeparator, tabNumber); 753 } 754 if (runtimeVisibleAnnotationsAttribute != null) { 755 disassembleAsModifier((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 756 writeNewLine(buffer, lineSeparator, tabNumber); 757 } 758 } 759 decodeModifiersForField(buffer, fieldInfo.getAccessFlags()); 760 if (fieldInfo.isSynthetic()) { 761 buffer.append("synthetic"); //$NON-NLS-1$ 762 buffer.append(Messages.disassembler_space); 763 } 764 buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode)); 765 buffer.append(' '); 766 buffer.append(new String(fieldInfo.getName())); 767 ConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute(); 768 if (constantValueAttribute != null) { 769 buffer.append(Messages.disassembler_fieldhasconstant); 770 ConstantPoolEntry constantPoolEntry = constantValueAttribute.getConstantValue(); 771 switch (constantPoolEntry.getKind()) { 772 case ConstantPoolConstant.CONSTANT_Long : 773 buffer.append(constantPoolEntry.getLongValue() + "L"); //$NON-NLS-1$ 774 break; 775 case ConstantPoolConstant.CONSTANT_Float : 776 buffer.append(constantPoolEntry.getFloatValue() + "f"); //$NON-NLS-1$ 777 break; 778 case ConstantPoolConstant.CONSTANT_Double : 779 buffer.append(constantPoolEntry.getDoubleValue()); 780 break; 781 case ConstantPoolConstant.CONSTANT_Integer : 782 switch (fieldDescriptor[0]) { 783 case 'C' : 784 buffer.append("'" + (char) constantPoolEntry.getIntegerValue() + "'"); //$NON-NLS-1$//$NON-NLS-2$ 785 break; 786 case 'Z' : 787 buffer.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$ 788 break; 789 case 'B' : 790 buffer.append(constantPoolEntry.getIntegerValue()); 791 break; 792 case 'S' : 793 buffer.append(constantPoolEntry.getIntegerValue()); 794 break; 795 case 'I' : 796 buffer.append(constantPoolEntry.getIntegerValue()); 797 } 798 break; 799 case ConstantPoolConstant.CONSTANT_String : 800 buffer.append("\"" + decodeStringValue(constantPoolEntry.getStringValue()) + "\"");//$NON-NLS-1$//$NON-NLS-2$ 801 } 802 } 803 buffer.append(Messages.disassembler_endoffieldheader); 804 if (checkMode(mode, DETAILED)) { 805 if (runtimeVisibleAnnotationsAttribute != null) { 806 disassemble((RuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 807 } 808 if (runtimeInvisibleAnnotationsAttribute != null) { 809 disassemble((RuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); 810 } 811 } 812 } 813 disassemble(InnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber)814 private void disassemble(InnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { 815 writeNewLine(buffer, lineSeparator, tabNumber); 816 buffer.append(Messages.disassembler_innerattributesheader); 817 writeNewLine(buffer, lineSeparator, tabNumber + 1); 818 InnerClassesAttributeEntry[] innerClassesAttributeEntries = innerClassesAttribute.getInnerClassAttributesEntries(); 819 int length = innerClassesAttributeEntries.length; 820 int innerClassNameIndex, outerClassNameIndex, innerNameIndex, accessFlags; 821 InnerClassesAttributeEntry innerClassesAttributeEntry; 822 if (length > 1) { 823 final char[] EMPTY_CHAR_ARRAY = Utility.EMPTY_STRING.toCharArray(); 824 Arrays.sort(innerClassesAttributeEntries, (o1, o2) -> { 825 final char[] innerClassName1 = o1.getInnerClassName(); 826 final char[] innerClassName2 = o2.getInnerClassName(); 827 final char[] innerName1 = o1.getInnerName(); 828 final char[] innerName2 = o2.getInnerName(); 829 final char[] outerClassName1 = o1.getOuterClassName(); 830 final char[] outerClassName2 = o2.getOuterClassName(); 831 StringBuilder buffer1 = new StringBuilder(); 832 buffer1.append(innerClassName1 == null ? EMPTY_CHAR_ARRAY : innerClassName1); 833 buffer1.append(innerName1 == null ? EMPTY_CHAR_ARRAY : innerName1); 834 buffer1.append(outerClassName1 == null ? EMPTY_CHAR_ARRAY : outerClassName1); 835 StringBuilder buffer2 = new StringBuilder(); 836 buffer2.append(innerClassName2 == null ? EMPTY_CHAR_ARRAY : innerClassName2); 837 buffer2.append(innerName2 == null ? EMPTY_CHAR_ARRAY : innerName2); 838 buffer2.append(outerClassName2 == null ? EMPTY_CHAR_ARRAY : outerClassName2); 839 return buffer1.toString().compareTo(buffer2.toString()); 840 }); 841 } 842 for (int i = 0; i < length; i++) { 843 if (i != 0) { 844 buffer.append(Messages.disassembler_comma); 845 writeNewLine(buffer, lineSeparator, tabNumber + 1); 846 } 847 innerClassesAttributeEntry = innerClassesAttributeEntries[i]; 848 innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex(); 849 outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex(); 850 innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex(); 851 accessFlags = innerClassesAttributeEntry.getAccessFlags(); 852 buffer.append(Messages.disassembler_openinnerclassentry).append(Messages.disassembler_inner_class_info_name); 853 if (innerClassNameIndex != 0) { 854 buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getInnerClassName()); 855 } 856 buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space).append(Messages.disassembler_outer_class_info_name); 857 if (outerClassNameIndex != 0) { 858 buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getOuterClassName()); 859 } 860 writeNewLine(buffer, lineSeparator, tabNumber); 861 dumpTab(tabNumber, buffer); 862 buffer.append(Messages.disassembler_space); 863 buffer.append(Messages.disassembler_inner_name); 864 if (innerNameIndex != 0) { 865 buffer.append(Messages.disassembler_space).append(innerClassesAttributeEntry.getInnerName()); 866 } 867 buffer.append(Messages.disassembler_comma).append(Messages.disassembler_space).append(Messages.disassembler_inner_accessflags).append(accessFlags).append(Messages.disassembler_space); 868 decodeModifiersForInnerClasses(buffer, accessFlags, true); 869 buffer.append(Messages.disassembler_closeinnerclassentry); 870 } 871 } 872 disassemble(int index, ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)873 private void disassemble(int index, ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 874 Annotation[] annotations = parameterAnnotation.getAnnotations(); 875 writeNewLine(buffer, lineSeparator, tabNumber + 1); 876 buffer.append(NLS.bind(Messages.disassembler_parameterannotationentrystart, new String[] {Integer.toString(index), Integer.toString(annotations.length)})); 877 for (Annotation annotation : annotations) { 878 disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode); 879 } 880 } 881 disassemble(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)882 private void disassemble(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 883 writeNewLine(buffer, lineSeparator, tabNumber + 1); 884 buffer.append(Messages.disassembler_runtimeinvisibleannotationsattributeheader); 885 Annotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations(); 886 for (Annotation annotation : annotations) { 887 disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode); 888 } 889 } 890 disassemble(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)891 private void disassemble(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 892 writeNewLine(buffer, lineSeparator, tabNumber + 1); 893 buffer.append(Messages.disassembler_runtimeinvisibleparameterannotationsattributeheader); 894 ParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations(); 895 for (int i = 0, max = parameterAnnotations.length; i < max; i++) { 896 disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); 897 } 898 } 899 disassemble(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)900 private void disassemble(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 901 writeNewLine(buffer, lineSeparator, tabNumber + 1); 902 buffer.append(Messages.disassembler_runtimevisibleannotationsattributeheader); 903 Annotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations(); 904 for (Annotation annotation : annotations) { 905 disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode); 906 } 907 } 908 disassemble(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)909 private void disassemble(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 910 writeNewLine(buffer, lineSeparator, tabNumber + 1); 911 buffer.append(Messages.disassembler_runtimevisibleparameterannotationsattributeheader); 912 ParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations(); 913 for (int i = 0, max = parameterAnnotations.length; i < max; i++) { 914 disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); 915 } 916 } 917 disassembleAsModifier(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)918 private void disassembleAsModifier(Annotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 919 final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.'); 920 buffer.append('@').append(returnClassName(Signature.toCharArray(typeName), '.', mode)); 921 final AnnotationComponent[] components = annotation.getComponents(); 922 final int length = components.length; 923 if (length != 0) { 924 buffer.append('('); 925 for (int i = 0; i < length; i++) { 926 if (i > 0) { 927 buffer.append(','); 928 writeNewLine(buffer, lineSeparator, tabNumber); 929 } 930 disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1, mode); 931 } 932 buffer.append(')'); 933 } 934 } 935 disassembleAsModifier(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)936 private void disassembleAsModifier(AnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 937 buffer.append(annotationComponent.getComponentName()).append('='); 938 disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode); 939 } 940 disassembleAsModifier(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)941 private void disassembleAsModifier(AnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 942 switch (annotationComponentValue.getTag()) { 943 case AnnotationComponentValue.BYTE_TAG : 944 case AnnotationComponentValue.CHAR_TAG : 945 case AnnotationComponentValue.DOUBLE_TAG : 946 case AnnotationComponentValue.FLOAT_TAG : 947 case AnnotationComponentValue.INTEGER_TAG : 948 case AnnotationComponentValue.LONG_TAG : 949 case AnnotationComponentValue.SHORT_TAG : 950 case AnnotationComponentValue.BOOLEAN_TAG : 951 case AnnotationComponentValue.STRING_TAG : 952 ConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue(); 953 String value = null; 954 switch (constantPoolEntry.getKind()) { 955 case ConstantPoolConstant.CONSTANT_Long : 956 value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$ 957 break; 958 case ConstantPoolConstant.CONSTANT_Float : 959 value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$ 960 break; 961 case ConstantPoolConstant.CONSTANT_Double : 962 value = Double.toString(constantPoolEntry.getDoubleValue()); 963 break; 964 case ConstantPoolConstant.CONSTANT_Integer : 965 switch (annotationComponentValue.getTag()) { 966 case AnnotationComponentValue.CHAR_TAG : 967 value = "'" + (char) constantPoolEntry.getIntegerValue() + "'"; //$NON-NLS-1$//$NON-NLS-2$ 968 break; 969 case AnnotationComponentValue.BOOLEAN_TAG : 970 value = constantPoolEntry.getIntegerValue() == 1 ? "true" : "false";//$NON-NLS-1$//$NON-NLS-2$ 971 break; 972 case AnnotationComponentValue.BYTE_TAG : 973 value = "(byte) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 974 break; 975 case AnnotationComponentValue.SHORT_TAG : 976 value = "(short) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 977 break; 978 case AnnotationComponentValue.INTEGER_TAG : 979 value = "(int) " + constantPoolEntry.getIntegerValue(); //$NON-NLS-1$ 980 } 981 break; 982 case ConstantPoolConstant.CONSTANT_Utf8 : 983 value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$ 984 } 985 buffer.append(value); 986 break; 987 case AnnotationComponentValue.ENUM_TAG : 988 final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.'); 989 final char[] constantName = annotationComponentValue.getEnumConstantName(); 990 buffer.append(returnClassName(Signature.toCharArray(typeName), '.', mode)).append('.').append(constantName); 991 break; 992 case AnnotationComponentValue.CLASS_TAG : 993 constantPoolEntry = annotationComponentValue.getClassInfo(); 994 final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.'); 995 buffer.append(returnClassName(Signature.toCharArray(className), '.', mode)); 996 break; 997 case AnnotationComponentValue.ANNOTATION_TAG : 998 Annotation annotation = annotationComponentValue.getAnnotationValue(); 999 disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode); 1000 break; 1001 case AnnotationComponentValue.ARRAY_TAG : 1002 final AnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues(); 1003 buffer.append('{'); 1004 for (int i = 0, max = annotationComponentValues.length; i < max; i++) { 1005 if (i > 0) { 1006 buffer.append(','); 1007 } 1008 disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1, mode); 1009 } 1010 buffer.append('}'); 1011 } 1012 } 1013 disassembleAsModifier(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1014 private void disassembleAsModifier(AnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 1015 AnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue(); 1016 disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1, mode); 1017 } 1018 disassembleAsModifier(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1019 private void disassembleAsModifier(RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 1020 for (Annotation annotation : runtimeInvisibleAnnotationsAttribute.getAnnotations()) { 1021 disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode); 1022 } 1023 } 1024 disassembleAsModifier(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode)1025 private void disassembleAsModifier(RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode) { 1026 ParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations(); 1027 if (parameterAnnotations.length > index) { 1028 disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode); 1029 } 1030 } 1031 disassembleAsModifier(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode)1032 private void disassembleAsModifier(RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode) { 1033 ParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations(); 1034 if (parameterAnnotations.length > index) { 1035 disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode); 1036 } 1037 } 1038 disassembleAsModifier(ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1039 private void disassembleAsModifier(ParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 1040 Annotation[] annotations = parameterAnnotation.getAnnotations(); 1041 for (int i = 0, max = annotations.length; i < max; i++) { 1042 if (i > 0) { 1043 buffer.append(' '); 1044 } 1045 disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); 1046 } 1047 } 1048 disassembleAsModifier(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode)1049 private void disassembleAsModifier(RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { 1050 Annotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations(); 1051 for (int i = 0, max = annotations.length; i < max; i++) { 1052 if (i > 0) { 1053 writeNewLine(buffer, lineSeparator, tabNumber); 1054 } 1055 disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); 1056 } 1057 } 1058 disassembleTypeMembers(ClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum)1059 private void disassembleTypeMembers(ClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum) { 1060 FieldInfo[] fields = classFileReader.getFieldInfos(); 1061 // sort fields 1062 Arrays.sort(fields, (fieldInfo1, fieldInfo2) -> { 1063 int compare = new String(fieldInfo1.getName()).compareTo(new String(fieldInfo2.getName())); 1064 if (compare == 0) { 1065 return new String(fieldInfo1.getDescriptor()).compareTo(new String(fieldInfo2.getDescriptor())); 1066 } 1067 return compare; 1068 }); 1069 for (FieldInfo field : fields) { 1070 writeNewLine(buffer, lineSeparator, tabNumber); 1071 disassemble(field, buffer, lineSeparator, tabNumber, mode); 1072 } 1073 MethodInfo[] methods = classFileReader.getMethodInfos(); 1074 // sort methods 1075 Arrays.sort(methods, (methodInfo1, methodInfo2) -> { 1076 int compare = new String(methodInfo1.getName()).compareTo(new String(methodInfo2.getName())); 1077 if (compare == 0) { 1078 return new String(methodInfo1.getDescriptor()).compareTo(new String(methodInfo2.getDescriptor())); 1079 } 1080 return compare; 1081 }); 1082 for (MethodInfo method : methods) { 1083 writeNewLine(buffer, lineSeparator, tabNumber); 1084 disassemble(classFileReader, className, method, buffer, lineSeparator, tabNumber, mode); 1085 } 1086 } 1087 dumpTab(int tabNumber, StringBuffer buffer)1088 private final void dumpTab(int tabNumber, StringBuffer buffer) { 1089 for (int i = 0; i < tabNumber; i++) { 1090 buffer.append(Messages.disassembler_indentation); 1091 } 1092 } 1093 getEnclosingMethodAttribute(ClassFileReader classFileReader)1094 private EnclosingMethodAttribute getEnclosingMethodAttribute(ClassFileReader classFileReader) { 1095 for (ClassFileAttribute attribute : classFileReader.getAttributes()) { 1096 if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.ENCLOSING_METHOD)) { 1097 return (EnclosingMethodAttribute) attribute; 1098 } 1099 } 1100 return null; 1101 } 1102 getSignatureForField(char[] fieldDescriptor)1103 private char[] getSignatureForField(char[] fieldDescriptor) { 1104 char[] newFieldDescriptor = CharOperation.replaceOnCopy(fieldDescriptor, '/', '.'); 1105 newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '%'); 1106 char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor); 1107 CharOperation.replace(fieldDescriptorSignature, '%', '$'); 1108 return fieldDescriptorSignature; 1109 } 1110 isDeprecated(ClassFileReader classFileReader)1111 private boolean isDeprecated(ClassFileReader classFileReader) { 1112 for (ClassFileAttribute attribute : classFileReader.getAttributes()) { 1113 if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.DEPRECATED)) { 1114 return true; 1115 } 1116 } 1117 return false; 1118 } 1119 isSynthetic(ClassFileReader classFileReader)1120 private boolean isSynthetic(ClassFileReader classFileReader) { 1121 int flags = classFileReader.getAccessFlags(); 1122 if ((flags & IModifierConstants.ACC_SYNTHETIC) != 0) { 1123 return true; 1124 } 1125 for (ClassFileAttribute attribute : classFileReader.getAttributes()) { 1126 if (Arrays.equals(attribute.getAttributeName(), AttributeNamesConstants.SYNTHETIC)) { 1127 return true; 1128 } 1129 } 1130 return false; 1131 } 1132 checkMode(int mode, int flag)1133 private boolean checkMode(int mode, int flag) { 1134 return (mode & flag) != 0; 1135 } 1136 isCompact(int mode)1137 private boolean isCompact(int mode) { 1138 return (mode & Disassembler.COMPACT) != 0; 1139 } 1140 returnClassName(char[] classInfoName, char separator, int mode)1141 private char[] returnClassName(char[] classInfoName, char separator, int mode) { 1142 if (classInfoName.length == 0) { 1143 return CharOperation.NO_CHAR; 1144 } else if (isCompact(mode)) { 1145 int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName); 1146 if (lastIndexOfSlash != -1) { 1147 return CharOperation.subarray(classInfoName, lastIndexOfSlash + 1, classInfoName.length); 1148 } 1149 } 1150 return classInfoName; 1151 } 1152 writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber)1153 private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) { 1154 buffer.append(lineSeparator); 1155 dumpTab(tabNumber, buffer); 1156 } 1157 } 1158