| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for |
| * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) |
| * Jesper Steen Moeller - Contributions for: |
| * Bug 406973 - [compiler] Parse MethodParameters attribute |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.core.util; |
| |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.core.util.*; |
| import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; |
| |
| /** |
| * Disassembler of .class files. It generates an output in the Writer that looks close to |
| * the javap output. |
| */ |
| public class Disassembler extends ClassFileBytesDisassembler { |
| |
| private static final char[] ANY_EXCEPTION = Messages.classfileformat_anyexceptionhandler.toCharArray(); |
| private static final String VERSION_UNKNOWN = Messages.classfileformat_versionUnknown; |
| |
| private boolean appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier) { |
| if ((accessFlags & modifierConstant) != 0) { |
| if (!firstModifier) { |
| buffer.append(Messages.disassembler_space); |
| } |
| if (firstModifier) { |
| firstModifier = false; |
| } |
| buffer.append(modifier); |
| } |
| return firstModifier; |
| } |
| |
| private void decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits) { |
| decodeModifiers(buffer, accessFlags, false, false, checkBits); |
| } |
| |
| private void decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits) { |
| if (checkBits == null) return; |
| boolean firstModifier = true; |
| for (int i = 0, max = checkBits.length; i < max; i++) { |
| switch(checkBits[i]) { |
| case IModifierConstants.ACC_PUBLIC : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_PROTECTED : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_PRIVATE : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_ABSTRACT : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_STATIC : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_FINAL : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_SYNCHRONIZED : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_NATIVE : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_STRICT : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_TRANSIENT : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_VOLATILE : |
| // case IModifierConstants.ACC_BRIDGE : |
| if (asBridge) { |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$ |
| } else { |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$ |
| } |
| break; |
| case IModifierConstants.ACC_ENUM : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_SYNTHETIC : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNTHETIC, "synthetic", firstModifier); //$NON-NLS-1$ |
| break; |
| case IModifierConstants.ACC_MANDATED : |
| firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_MANDATED, "mandated", firstModifier); //$NON-NLS-1$ |
| break; |
| } |
| } |
| if (!firstModifier) { |
| if (!printDefault) buffer.append(Messages.disassembler_space); |
| } else if (printDefault) { |
| // no modifier: package default visibility |
| buffer.append("default"); //$NON-NLS-1$ |
| } |
| } |
| |
| private void decodeModifiersForField(StringBuffer buffer, int accessFlags) { |
| 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 |
| }); |
| } |
| |
| private void decodeModifiersForFieldForWorkingCopy(StringBuffer buffer, int accessFlags) { |
| 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, |
| }); |
| } |
| |
| private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault) { |
| 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, |
| }); |
| } |
| |
| private final void decodeModifiersForMethod(StringBuffer buffer, int accessFlags) { |
| 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, |
| }); |
| } |
| |
| private final void decodeModifiersForMethodParameters(StringBuffer buffer, int accessFlags) { |
| decodeModifiers(buffer, accessFlags, false, true, new int[] { |
| IModifierConstants.ACC_FINAL, |
| IModifierConstants.ACC_MANDATED, |
| IModifierConstants.ACC_SYNTHETIC, |
| }); |
| } |
| |
| private final void decodeModifiersForType(StringBuffer buffer, int accessFlags) { |
| decodeModifiers(buffer, accessFlags, new int[] { |
| IModifierConstants.ACC_PUBLIC, |
| IModifierConstants.ACC_ABSTRACT, |
| IModifierConstants.ACC_FINAL, |
| }); |
| } |
| public static String escapeString(String s) { |
| return decodeStringValue(s); |
| } |
| |
| static String decodeStringValue(char[] chars) { |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, max = chars.length; i < max; i++) { |
| char c = chars[i]; |
| org.eclipse.jdt.internal.compiler.util.Util.appendEscapedChar(buffer, c, true); |
| } |
| return buffer.toString(); |
| } |
| |
| private static void escapeChar(StringBuffer buffer, char c) { |
| org.eclipse.jdt.internal.compiler.util.Util.appendEscapedChar(buffer, c, false); |
| } |
| |
| static String decodeStringValue(String s) { |
| return decodeStringValue(s.toCharArray()); |
| } |
| |
| /** |
| * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String) |
| */ |
| public String disassemble(byte[] classFileBytes, String lineSeparator) throws ClassFormatException { |
| try { |
| return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, ClassFileBytesDisassembler.DEFAULT); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new ClassFormatException(e.getMessage(), e); |
| } |
| } |
| |
| /** |
| * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int) |
| */ |
| public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException { |
| try { |
| return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, mode); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new ClassFormatException(e.getMessage(), e); |
| } |
| } |
| |
| private void disassemble(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| final int typeIndex = annotation.getTypeIndex(); |
| final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.'); |
| buffer.append( |
| Messages.bind(Messages.disassembler_annotationentrystart, new String[] { |
| Integer.toString(typeIndex), |
| new String(returnClassName(Signature.toCharArray(typeName), '.', mode)) |
| })); |
| final IAnnotationComponent[] components = annotation.getComponents(); |
| for (int i = 0, max = components.length; i < max; i++) { |
| disassemble(components[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_annotationentryend); |
| } |
| |
| private void disassemble(IExtendedAnnotation extendedAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| final int typeIndex = extendedAnnotation.getTypeIndex(); |
| final char[] typeName = CharOperation.replaceOnCopy(extendedAnnotation.getTypeName(), '/', '.'); |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotationentrystart, new String[] { |
| Integer.toString(typeIndex), |
| new String(returnClassName(Signature.toCharArray(typeName), '.', mode)) |
| })); |
| final IAnnotationComponent[] components = extendedAnnotation.getComponents(); |
| for (int i = 0, max = components.length; i < max; i++) { |
| disassemble(components[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| int targetType = extendedAnnotation.getTargetType(); |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_targetType, new String[] { |
| Integer.toHexString(targetType), |
| getTargetType(targetType), |
| })); |
| switch(targetType) { |
| case IExtendedAnnotationConstants.METHOD_RECEIVER : |
| case IExtendedAnnotationConstants.METHOD_RETURN: |
| case IExtendedAnnotationConstants.FIELD : |
| break; |
| default: |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| disassembleTargetTypeContents(false, targetType, extendedAnnotation, buffer, lineSeparator, tabNumber, mode); |
| } |
| disassembleTypePathContents(targetType, extendedAnnotation, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_extendedannotationentryend); |
| } |
| |
| private void disassembleTypePathContents(int targetType, IExtendedAnnotation extendedAnnotation,StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| int[][] typepath = extendedAnnotation.getTypePath(); |
| if (typepath.length != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_typepath, new String[] { |
| toTypePathString(typepath), |
| })); |
| } |
| } |
| private void disassembleTargetTypeContents(boolean insideWildcard, int targetType, IExtendedAnnotation extendedAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| switch(targetType) { |
| case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER : |
| case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_type_parameter, new String[] { |
| Integer.toString(extendedAnnotation.getTypeParameterIndex()), |
| })); |
| break; |
| case IExtendedAnnotationConstants.CLASS_EXTENDS : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_classextendsimplements, new String[] { |
| Integer.toString(extendedAnnotation.getAnnotationTypeIndex()), |
| })); |
| break; |
| |
| case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND : |
| case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_type_parameter_with_bound, new String[] { |
| Integer.toString(extendedAnnotation.getTypeParameterIndex()), |
| Integer.toString(extendedAnnotation.getTypeParameterBoundIndex()), |
| })); |
| break; |
| case IExtendedAnnotationConstants.FIELD : |
| case IExtendedAnnotationConstants.METHOD_RETURN : |
| case IExtendedAnnotationConstants.METHOD_RECEIVER : |
| break; |
| case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_method_parameter, new String[] { |
| Integer.toString(extendedAnnotation.getParameterIndex()), |
| })); |
| break; |
| case IExtendedAnnotationConstants.THROWS : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_throws, new String[] { |
| Integer.toString(extendedAnnotation.getAnnotationTypeIndex()), |
| })); |
| break; |
| |
| case IExtendedAnnotationConstants.LOCAL_VARIABLE : |
| case IExtendedAnnotationConstants.RESOURCE_VARIABLE : |
| buffer.append(Messages.disassembler_localvariabletargetheader); |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| int localVariableTableSize = extendedAnnotation.getLocalVariableRefenceInfoLength(); |
| ILocalVariableReferenceInfo[] localVariableTable = extendedAnnotation.getLocalVariableTable(); |
| for (int i = 0; i < localVariableTableSize; i++) { |
| if (i != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| } |
| ILocalVariableReferenceInfo info = localVariableTable[i]; |
| int index= info.getIndex(); |
| int startPC = info.getStartPC(); |
| int length = info.getLength(); |
| buffer.append(Messages.bind(Messages.classfileformat_localvariablereferenceinfoentry, |
| new String[] { |
| Integer.toString(startPC), |
| Integer.toString(startPC + length), |
| Integer.toString(index), |
| })); |
| } |
| break; |
| case IExtendedAnnotationConstants.EXCEPTION_PARAMETER : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_exception_table_index, new String[] { |
| Integer.toString(extendedAnnotation.getExceptionTableIndex()), |
| })); |
| break; |
| |
| case IExtendedAnnotationConstants.INSTANCEOF : |
| case IExtendedAnnotationConstants.NEW : |
| case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE : |
| case IExtendedAnnotationConstants.METHOD_REFERENCE : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_offset, new String[] { |
| Integer.toString(extendedAnnotation.getOffset()), |
| })); |
| break; |
| case IExtendedAnnotationConstants.CAST : |
| case IExtendedAnnotationConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : |
| case IExtendedAnnotationConstants.METHOD_INVOCATION_TYPE_ARGUMENT : |
| case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : |
| case IExtendedAnnotationConstants.METHOD_REFERENCE_TYPE_ARGUMENT : |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_offset, new String[] { |
| Integer.toString(extendedAnnotation.getOffset()), |
| })); |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_type_argument, new String[] { |
| Integer.toString(extendedAnnotation.getAnnotationTypeIndex()), |
| })); |
| break; |
| } |
| } |
| private String getTargetType(int targetType) { |
| switch(targetType) { |
| case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER : |
| return "CLASS_TYPE_PARAMETER"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER : |
| return "METHOD_TYPE_PARAMETER"; //$NON-NLS-1$ |
| |
| case IExtendedAnnotationConstants.CLASS_EXTENDS : |
| return "CLASS_EXTENDS"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND : |
| return "CLASS_TYPE_PARAMETER_BOUND"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND : |
| return "METHOD_TYPE_PARAMETER_BOUND"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.FIELD : |
| return "FIELD"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_RETURN : |
| return "METHOD_RETURN"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_RECEIVER : |
| return "METHOD_RECEIVER"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER : |
| return "METHOD_FORMAL_PARAMETER"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.THROWS : |
| return "THROWS"; //$NON-NLS-1$ |
| |
| case IExtendedAnnotationConstants.LOCAL_VARIABLE : |
| return "LOCAL_VARIABLE"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.RESOURCE_VARIABLE : |
| return "RESOURCE_VARIABLE"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.EXCEPTION_PARAMETER : |
| return "EXCEPTION_PARAMETER"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.INSTANCEOF : |
| return "INSTANCEOF"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.NEW : |
| return "NEW"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE : |
| return "CONSTRUCTOR_REFERENCE"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_REFERENCE : |
| return "METHOD_REFERENCE"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.CAST : |
| return "CAST"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : |
| return "CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_INVOCATION_TYPE_ARGUMENT : |
| return "METHOD_INVOCATION_TYPE_ARGUMENT"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : |
| return "CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT"; //$NON-NLS-1$ |
| case IExtendedAnnotationConstants.METHOD_REFERENCE_TYPE_ARGUMENT : |
| return "METHOD_REFERENCE_TYPE_ARGUMENT"; //$NON-NLS-1$ |
| default: |
| return "UNKNOWN"; //$NON-NLS-1$ |
| } |
| } |
| |
| |
| private void disassemble(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append( |
| Messages.bind(Messages.disassembler_annotationcomponent, |
| new String[] { |
| Integer.toString(annotationComponent.getComponentNameIndex()), |
| new String(annotationComponent.getComponentName()) |
| })); |
| disassemble(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| |
| private void disassemble(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| switch(annotationComponentValue.getTag()) { |
| case IAnnotationComponentValue.BYTE_TAG: |
| case IAnnotationComponentValue.CHAR_TAG: |
| case IAnnotationComponentValue.DOUBLE_TAG: |
| case IAnnotationComponentValue.FLOAT_TAG: |
| case IAnnotationComponentValue.INTEGER_TAG: |
| case IAnnotationComponentValue.LONG_TAG: |
| case IAnnotationComponentValue.SHORT_TAG: |
| case IAnnotationComponentValue.BOOLEAN_TAG: |
| case IAnnotationComponentValue.STRING_TAG: |
| IConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue(); |
| String value = null; |
| switch(constantPoolEntry.getKind()) { |
| case IConstantPoolConstant.CONSTANT_Long : |
| value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Float : |
| value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Double : |
| value = Double.toString(constantPoolEntry.getDoubleValue()); |
| break; |
| case IConstantPoolConstant.CONSTANT_Integer: |
| StringBuffer temp = new StringBuffer(); |
| switch(annotationComponentValue.getTag()) { |
| case IAnnotationComponentValue.CHAR_TAG : |
| temp.append('\''); |
| escapeChar(temp, (char) constantPoolEntry.getIntegerValue()); |
| temp.append('\''); |
| break; |
| case IAnnotationComponentValue.BOOLEAN_TAG : |
| temp.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$ |
| break; |
| case IAnnotationComponentValue.BYTE_TAG : |
| temp.append("(byte) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| break; |
| case IAnnotationComponentValue.SHORT_TAG : |
| temp.append("(short) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| break; |
| case IAnnotationComponentValue.INTEGER_TAG : |
| temp.append("(int) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| } |
| value = String.valueOf(temp); |
| break; |
| case IConstantPoolConstant.CONSTANT_Utf8: |
| value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$ |
| } |
| buffer.append(Messages.bind(Messages.disassembler_annotationdefaultvalue, value)); |
| break; |
| case IAnnotationComponentValue.ENUM_TAG: |
| final int enumConstantTypeNameIndex = annotationComponentValue.getEnumConstantTypeNameIndex(); |
| final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.'); |
| final int enumConstantNameIndex = annotationComponentValue.getEnumConstantNameIndex(); |
| final char[] constantName = annotationComponentValue.getEnumConstantName(); |
| buffer.append(Messages.bind(Messages.disassembler_annotationenumvalue, |
| new String[] { |
| Integer.toString(enumConstantTypeNameIndex), |
| Integer.toString(enumConstantNameIndex), |
| new String(returnClassName(Signature.toCharArray(typeName), '.', mode)), |
| new String(constantName) |
| })); |
| break; |
| case IAnnotationComponentValue.CLASS_TAG: |
| final int classIndex = annotationComponentValue.getClassInfoIndex(); |
| constantPoolEntry = annotationComponentValue.getClassInfo(); |
| final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.'); |
| buffer.append(Messages.bind(Messages.disassembler_annotationclassvalue, |
| new String[] { |
| Integer.toString(classIndex), |
| new String(returnClassName(Signature.toCharArray(className), '.', mode)) |
| })); |
| break; |
| case IAnnotationComponentValue.ANNOTATION_TAG: |
| buffer.append(Messages.disassembler_annotationannotationvalue); |
| IAnnotation annotation = annotationComponentValue.getAnnotationValue(); |
| disassemble(annotation, buffer, lineSeparator, tabNumber + 1, mode); |
| break; |
| case IAnnotationComponentValue.ARRAY_TAG: |
| buffer.append(Messages.disassembler_annotationarrayvaluestart); |
| final IAnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues(); |
| for (int i = 0, max = annotationComponentValues.length; i < max; i++) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| disassemble(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_annotationarrayvalueend); |
| } |
| } |
| |
| private void disassemble(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_annotationdefaultheader); |
| IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue(); |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| disassemble(componentValue, buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| |
| private void disassemble(IClassFileAttribute classFileAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.bind(Messages.disassembler_genericattributeheader, |
| new String[] { |
| new String(classFileAttribute.getAttributeName()), |
| Long.toString(classFileAttribute.getAttributeLength()) |
| })); |
| } |
| |
| private void disassemble(IMethodParametersAttribute methodParametersAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| tabNumber += 2; |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| buffer.append(Messages.disassembler_methodparametersheader); |
| for (int i = 0, length = methodParametersAttribute.getMethodParameterLength(); i < length; ++i) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| short accessFlags = methodParametersAttribute.getAccessFlags(i); |
| decodeModifiersForMethodParameters(buffer, accessFlags); |
| char [] parameterName = methodParametersAttribute.getParameterName(i); |
| if (parameterName == null) |
| parameterName = Messages.disassembler_anonymousparametername.toCharArray(); |
| buffer.append(parameterName); |
| } |
| } |
| |
| private void disassembleEnumConstructor(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute(); |
| IMethodParametersAttribute methodParametersAttribute = (IMethodParametersAttribute) Util.getAttribute(methodInfo, IAttributeNamesConstants.METHOD_PARAMETERS); |
| char[] methodDescriptor = methodInfo.getDescriptor(); |
| final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); |
| // disassemble compact version of annotations |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| final int accessFlags = methodInfo.getAccessFlags(); |
| decodeModifiersForMethod(buffer, accessFlags & IModifierConstants.ACC_PRIVATE); |
| CharOperation.replace(methodDescriptor, '/', '.'); |
| final boolean isVarArgs = (accessFlags & IModifierConstants.ACC_VARARGS) != 0; |
| final char[] signature = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), getParameterNames(methodDescriptor, codeAttribute, methodParametersAttribute, accessFlags) , !checkMode(mode, COMPACT), false, isVarArgs); |
| int index = CharOperation.indexOf(',', signature); |
| index = CharOperation.indexOf(',', signature, index + 1); |
| buffer.append(signature, 0, CharOperation.indexOf('(', signature) + 1); |
| buffer.append(signature, index + 2, signature.length - index - 2); |
| IExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute(); |
| if (exceptionAttribute != null) { |
| buffer.append(" throws "); //$NON-NLS-1$ |
| char[][] exceptionNames = exceptionAttribute.getExceptionNames(); |
| int length = exceptionNames.length; |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space); |
| } |
| char[] exceptionName = exceptionNames[i]; |
| CharOperation.replace(exceptionName, '/', '.'); |
| buffer.append(returnClassName(exceptionName, '.', mode)); |
| } |
| } |
| if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0) |
| && ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) { |
| buffer.append(" {"); //$NON-NLS-1$ |
| final char[] returnType = Signature.getReturnType(methodDescriptor); |
| if (returnType.length == 1) { |
| switch(returnType[0]) { |
| case 'V' : |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| break; |
| case 'I' : |
| case 'B' : |
| case 'J' : |
| case 'D' : |
| case 'F' : |
| case 'S' : |
| case 'C' : |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return 0;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| break; |
| default : |
| // boolean |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return false;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } else { |
| // object |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return null;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| buffer.append('}'); |
| } else { |
| buffer.append(';'); |
| } |
| } |
| |
| /** |
| * Disassemble a method info header |
| */ |
| private void disassemble(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute(); |
| final char[] methodDescriptor = methodInfo.getDescriptor(); |
| final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE); |
| final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); |
| final IClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); |
| final IClassFileAttribute methodParametersAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.METHOD_PARAMETERS); |
| final IClassFileAttribute annotationDefaultAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.ANNOTATION_DEFAULT); |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| buffer.append(Messages.bind(Messages.classfileformat_methoddescriptor, |
| new String[] { |
| Integer.toString(methodInfo.getDescriptorIndex()), |
| new String(methodDescriptor) |
| })); |
| if (methodInfo.isDeprecated()) { |
| buffer.append(Messages.disassembler_deprecated); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| if (signatureAttribute != null) { |
| buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| if (codeAttribute != null) { |
| buffer.append(Messages.bind(Messages.classfileformat_stacksAndLocals, |
| new String[] { |
| Integer.toString(codeAttribute.getMaxStack()), |
| Integer.toString(codeAttribute.getMaxLocals()) |
| })); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } |
| if (checkMode(mode, DETAILED)) { |
| // disassemble compact version of annotations |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } |
| final int accessFlags = methodInfo.getAccessFlags(); |
| decodeModifiersForMethod(buffer, accessFlags); |
| if (methodInfo.isSynthetic() && !checkMode(mode, WORKING_COPY)) { |
| buffer.append("synthetic"); //$NON-NLS-1$ |
| buffer.append(Messages.disassembler_space); |
| } |
| CharOperation.replace(methodDescriptor, '/', '.'); |
| final boolean isVarArgs = isVarArgs(methodInfo); |
| char[] methodHeader = null; |
| char[][] parameterNames = null; |
| if (!methodInfo.isClinit()) { |
| parameterNames = getParameterNames(methodDescriptor, codeAttribute, (IMethodParametersAttribute)methodParametersAttribute, accessFlags); |
| } |
| if (methodInfo.isConstructor()) { |
| if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) { |
| final char[] signature = signatureAttribute.getSignature(); |
| CharOperation.replace(signature, '/', '.'); |
| disassembleGenericSignature(mode, buffer, signature); |
| buffer.append(' '); |
| methodHeader = Signature.toCharArray(signature, returnClassName(className, '.', COMPACT), parameterNames, !checkMode(mode, COMPACT), false, isVarArgs); |
| } else { |
| methodHeader = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), parameterNames, !checkMode(mode, COMPACT), false, isVarArgs); |
| } |
| } else if (methodInfo.isClinit()) { |
| methodHeader = Messages.bind(Messages.classfileformat_clinitname).toCharArray(); |
| } else { |
| if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) { |
| final char[] signature = signatureAttribute.getSignature(); |
| CharOperation.replace(signature, '/', '.'); |
| disassembleGenericSignature(mode, buffer, signature); |
| buffer.append(' '); |
| methodHeader = Signature.toCharArray(signature, methodInfo.getName(), parameterNames, !checkMode(mode, COMPACT), true, isVarArgs); |
| } else { |
| methodHeader = Signature.toCharArray(methodDescriptor, methodInfo.getName(), parameterNames, !checkMode(mode, COMPACT), true, isVarArgs); |
| } |
| } |
| if (checkMode(mode, DETAILED) && (runtimeInvisibleParameterAnnotationsAttribute != null || runtimeVisibleParameterAnnotationsAttribute != null)) { |
| IParameterAnnotation[] invisibleParameterAnnotations = null; |
| IParameterAnnotation[] visibleParameterAnnotations = null; |
| int length = -1; |
| if (runtimeInvisibleParameterAnnotationsAttribute != null) { |
| IRuntimeInvisibleParameterAnnotationsAttribute attribute = (IRuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute; |
| invisibleParameterAnnotations = attribute.getParameterAnnotations(); |
| length = invisibleParameterAnnotations.length; |
| if (length > 0) { |
| int parameterNamesLength = parameterNames.length; |
| if (length < parameterNamesLength) { |
| System.arraycopy(invisibleParameterAnnotations, 0, (invisibleParameterAnnotations = new IParameterAnnotation[parameterNamesLength]), 1, length); |
| length = parameterNamesLength; |
| } |
| } |
| } |
| if (runtimeVisibleParameterAnnotationsAttribute != null) { |
| IRuntimeVisibleParameterAnnotationsAttribute attribute = (IRuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute; |
| visibleParameterAnnotations = attribute.getParameterAnnotations(); |
| length = visibleParameterAnnotations.length; |
| if (length > 0) { |
| int parameterNamesLength = parameterNames.length; |
| if (length < parameterNamesLength) { |
| System.arraycopy(visibleParameterAnnotations, 0, (visibleParameterAnnotations = new IParameterAnnotation[parameterNamesLength]), 1, length); |
| length = parameterNamesLength; |
| } |
| } |
| } |
| int insertionPosition = CharOperation.indexOf('(', methodHeader) + 1; |
| int start = 0; |
| StringBuffer stringBuffer = new StringBuffer(); |
| stringBuffer.append(methodHeader, 0, insertionPosition); |
| for (int i = 0; i < length; i++) { |
| if (i > 0) { |
| stringBuffer.append(' '); |
| } |
| int stringBufferSize = stringBuffer.length(); |
| if (visibleParameterAnnotations != null) { |
| disassembleAsModifier(visibleParameterAnnotations, stringBuffer, i, lineSeparator, tabNumber, mode); |
| } |
| if (invisibleParameterAnnotations != null) { |
| if (stringBuffer.length() != stringBufferSize) { |
| stringBuffer.append(' '); |
| stringBufferSize = stringBuffer.length(); |
| } |
| disassembleAsModifier(invisibleParameterAnnotations, stringBuffer, i, lineSeparator, tabNumber, mode); |
| } |
| if (i == 0 && stringBuffer.length() != stringBufferSize) { |
| stringBuffer.append(' '); |
| } |
| start = insertionPosition; |
| insertionPosition = CharOperation.indexOf(',', methodHeader, start + 1) + 1; |
| if (insertionPosition == 0) { |
| stringBuffer.append(methodHeader, start, methodHeader.length - start); |
| } else { |
| stringBuffer.append(methodHeader, start, insertionPosition - start); |
| } |
| } |
| buffer.append(stringBuffer); |
| } else { |
| buffer.append(methodHeader); |
| } |
| IExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute(); |
| if (exceptionAttribute != null) { |
| buffer.append(" throws "); //$NON-NLS-1$ |
| char[][] exceptionNames = exceptionAttribute.getExceptionNames(); |
| int length = exceptionNames.length; |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space); |
| } |
| char[] exceptionName = exceptionNames[i]; |
| CharOperation.replace(exceptionName, '/', '.'); |
| buffer.append(returnClassName(exceptionName, '.', mode)); |
| } |
| } |
| if (checkMode(mode, DETAILED)) { |
| if (annotationDefaultAttribute != null) { |
| buffer.append(" default "); //$NON-NLS-1$ |
| disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| if (checkMode(mode, WORKING_COPY)) { |
| // put the annotation default attribute if needed |
| if (annotationDefaultAttribute != null) { |
| buffer.append(" default "); //$NON-NLS-1$ |
| disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0) |
| && ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) { |
| buffer.append(" {"); //$NON-NLS-1$ |
| final char[] returnType = Signature.getReturnType(methodDescriptor); |
| if (returnType.length == 1) { |
| switch(returnType[0]) { |
| case 'V' : |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| break; |
| case 'I' : |
| case 'B' : |
| case 'J' : |
| case 'D' : |
| case 'F' : |
| case 'S' : |
| case 'C' : |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return 0;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| break; |
| default : |
| // boolean |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return false;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } else { |
| // object |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append("return null;"); //$NON-NLS-1$ |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| buffer.append('}'); |
| } else { |
| buffer.append(';'); |
| } |
| } else { |
| buffer.append(Messages.disassembler_endofmethodheader); |
| } |
| |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| if (codeAttribute != null) { |
| disassemble(codeAttribute, parameterNames, methodDescriptor, (accessFlags & IModifierConstants.ACC_STATIC) != 0, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| if (methodParametersAttribute != null) { |
| disassemble((IMethodParametersAttribute)methodParametersAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| if (checkMode(mode, SYSTEM)) { |
| IClassFileAttribute[] attributes = methodInfo.getAttributes(); |
| int length = attributes.length; |
| if (length != 0) { |
| for (int i = 0; i < length; i++) { |
| IClassFileAttribute attribute = attributes[i]; |
| if (attribute != codeAttribute |
| && attribute != exceptionAttribute |
| && attribute != signatureAttribute |
| && attribute != annotationDefaultAttribute |
| && attribute != runtimeInvisibleAnnotationsAttribute |
| && attribute != runtimeVisibleAnnotationsAttribute |
| && attribute != runtimeInvisibleTypeAnnotationsAttribute |
| && attribute != runtimeVisibleTypeAnnotationsAttribute |
| && attribute != runtimeInvisibleParameterAnnotationsAttribute |
| && attribute != runtimeVisibleParameterAnnotationsAttribute |
| && attribute != methodParametersAttribute |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED) |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) { |
| disassemble(attribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } |
| } |
| if (annotationDefaultAttribute != null) { |
| disassemble((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeVisibleParameterAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleParameterAnnotationsAttribute) runtimeVisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeInvisibleParameterAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleParameterAnnotationsAttribute) runtimeInvisibleParameterAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeVisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeInvisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| } |
| |
| /** |
| * @see #disassemble(org.eclipse.jdt.core.util.IClassFileReader, java.lang.String, int) |
| */ |
| public String disassemble(IClassFileReader classFileReader, String lineSeparator) { |
| return disassemble(classFileReader, lineSeparator, ClassFileBytesDisassembler.DEFAULT); |
| } |
| |
| /** |
| * Answers back the disassembled string of the IClassFileReader according to the |
| * mode. |
| * This is an output quite similar to the javap tool. |
| * |
| * @param classFileReader The classFileReader to be disassembled |
| * @param lineSeparator the line separator to use. |
| * @param mode the mode used to disassemble the IClassFileReader |
| * |
| * @return the disassembled string of the IClassFileReader according to the mode |
| */ |
| public String disassemble(IClassFileReader classFileReader, String lineSeparator, int mode) { |
| if (classFileReader == null) return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING; |
| char[] className = classFileReader.getClassName(); |
| if (className == null) { |
| // incomplete initialization. We cannot go further. |
| return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING; |
| } |
| className= CharOperation.replaceOnCopy(className, '/', '.'); |
| final int classNameLength = className.length; |
| final int accessFlags = classFileReader.getAccessFlags(); |
| final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0; |
| |
| StringBuffer buffer = new StringBuffer(); |
| ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute(); |
| IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE); |
| ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute; |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| int minorVersion = classFileReader.getMinorVersion(); |
| int majorVersion = classFileReader.getMajorVersion(); |
| buffer.append(Messages.disassembler_begincommentline); |
| if (sourceAttribute != null) { |
| buffer.append(Messages.disassembler_sourceattributeheader); |
| buffer.append(sourceAttribute.getSourceFileName()); |
| } |
| String versionNumber = VERSION_UNKNOWN; |
| if (minorVersion == 3 && majorVersion == 45) { |
| versionNumber = JavaCore.VERSION_1_1; |
| } else if (minorVersion == 0 && majorVersion == 46) { |
| versionNumber = JavaCore.VERSION_1_2; |
| } else if (minorVersion == 0 && majorVersion == 47) { |
| versionNumber = JavaCore.VERSION_1_3; |
| } else if (minorVersion == 0 && majorVersion == 48) { |
| versionNumber = JavaCore.VERSION_1_4; |
| } else if (minorVersion == 0 && majorVersion == 49) { |
| versionNumber = JavaCore.VERSION_1_5; |
| } else if (minorVersion == 0 && majorVersion == 50) { |
| versionNumber = JavaCore.VERSION_1_6; |
| } else if (minorVersion == 0 && majorVersion == 51) { |
| versionNumber = JavaCore.VERSION_1_7; |
| } else if (minorVersion == 0 && majorVersion == 52) { |
| versionNumber = JavaCore.VERSION_1_8; |
| } |
| buffer.append( |
| Messages.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" : org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING)//$NON-NLS-1$ |
| })); |
| writeNewLine(buffer, lineSeparator, 0); |
| if (signatureAttribute != null) { |
| buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); |
| writeNewLine(buffer, lineSeparator, 0); |
| } |
| } |
| final int lastDotIndexInClassName = CharOperation.lastIndexOf('.', className); |
| |
| if (checkMode(mode, WORKING_COPY) && lastDotIndexInClassName != -1) { |
| // we print a package declaration |
| buffer.append("package ");//$NON-NLS-1$ |
| buffer.append(className, 0, lastDotIndexInClassName); |
| buffer.append(';'); |
| writeNewLine(buffer, lineSeparator, 0); |
| } |
| |
| IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute(); |
| IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); |
| IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); |
| IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); |
| IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); |
| |
| IClassFileAttribute bootstrapMethods = Util.getAttribute(classFileReader, IAttributeNamesConstants.BOOTSTRAP_METHODS); |
| |
| if (checkMode(mode, DETAILED)) { |
| // disassemble compact version of annotations |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| writeNewLine(buffer, lineSeparator, 0); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| writeNewLine(buffer, lineSeparator, 0); |
| } |
| } |
| boolean decoded = false; |
| if (isEnum && checkMode(mode, WORKING_COPY)) { |
| decodeModifiersForType(buffer, accessFlags & IModifierConstants.ACC_PUBLIC); |
| } else { |
| if (innerClassesAttribute != null) { |
| // search the right entry |
| IInnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries(); |
| for (int i = 0, max = entries.length; i < max ; i++) { |
| IInnerClassesAttributeEntry entry = entries[i]; |
| char[] innerClassName = entry.getInnerClassName(); |
| if (innerClassName != null) { |
| if (CharOperation.equals(classFileReader.getClassName(), innerClassName)) { |
| decodeModifiersForInnerClasses(buffer, entry.getAccessFlags(), false); |
| decoded = true; |
| } |
| } |
| } |
| } |
| if (!decoded) { |
| decodeModifiersForType(buffer, accessFlags); |
| if (isSynthetic(classFileReader)) { |
| buffer.append("synthetic"); //$NON-NLS-1$ |
| buffer.append(Messages.disassembler_space); |
| } |
| } |
| } |
| |
| final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0; |
| boolean isInterface = false; |
| if (isEnum) { |
| buffer.append("enum "); //$NON-NLS-1$ |
| } else if (classFileReader.isClass()) { |
| buffer.append("class "); //$NON-NLS-1$ |
| } else { |
| if (isAnnotation) { |
| buffer.append("@"); //$NON-NLS-1$ |
| } |
| buffer.append("interface "); //$NON-NLS-1$ |
| isInterface = true; |
| } |
| |
| if (checkMode(mode, WORKING_COPY)) { |
| // we print the simple class name |
| final int start = lastDotIndexInClassName + 1; |
| buffer.append(className, start, classNameLength - start); |
| className = CharOperation.subarray(className, start, classNameLength); |
| if (signatureAttribute != null) { |
| disassembleGenericSignature(mode, buffer, signatureAttribute.getSignature()); |
| } |
| } else { |
| buffer.append(className); |
| } |
| |
| char[] superclassName = classFileReader.getSuperclassName(); |
| if (superclassName != null) { |
| CharOperation.replace(superclassName, '/', '.'); |
| if (!isJavaLangObject(superclassName) && !isEnum) { |
| buffer.append(" extends "); //$NON-NLS-1$ |
| buffer.append(returnClassName(superclassName, '.', mode)); |
| } |
| } |
| if (!isAnnotation || !checkMode(mode, WORKING_COPY)) { |
| char[][] superclassInterfaces = classFileReader.getInterfaceNames(); |
| int length = superclassInterfaces.length; |
| if (length != 0) { |
| if (isInterface) { |
| buffer.append(" extends "); //$NON-NLS-1$ |
| } else { |
| buffer.append(" implements "); //$NON-NLS-1$ |
| } |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space); |
| } |
| char[] superinterface = superclassInterfaces[i]; |
| CharOperation.replace(superinterface, '/', '.'); |
| buffer |
| .append(returnClassName(superinterface, '.', mode)); |
| } |
| } |
| } |
| buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration)); |
| if (checkMode(mode, SYSTEM)) { |
| disassemble(classFileReader.getConstantPool(), buffer, lineSeparator, 1); |
| } |
| disassembleTypeMembers(classFileReader, className, buffer, lineSeparator, 1, mode, isEnum); |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| IClassFileAttribute[] attributes = classFileReader.getAttributes(); |
| int length = attributes.length; |
| IEnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader); |
| int remainingAttributesLength = length; |
| if (innerClassesAttribute != null) { |
| remainingAttributesLength--; |
| } |
| if (enclosingMethodAttribute != null) { |
| remainingAttributesLength--; |
| } |
| if (sourceAttribute != null) { |
| remainingAttributesLength--; |
| } |
| if (signatureAttribute != null) { |
| remainingAttributesLength--; |
| } |
| if (bootstrapMethods != null) { |
| remainingAttributesLength--; |
| } |
| if (innerClassesAttribute != null |
| || enclosingMethodAttribute != null |
| || bootstrapMethods != null |
| || remainingAttributesLength != 0) { |
| // this test is to ensure we don't insert more than one line separator |
| if (buffer.lastIndexOf(lineSeparator) != buffer.length() - lineSeparator.length()) { |
| writeNewLine(buffer, lineSeparator, 0); |
| } |
| } |
| if (innerClassesAttribute != null) { |
| disassemble(innerClassesAttribute, buffer, lineSeparator, 1); |
| } |
| if (enclosingMethodAttribute != null) { |
| disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0); |
| } |
| if (bootstrapMethods != null) { |
| disassemble((IBootstrapMethodsAttribute) bootstrapMethods, buffer, lineSeparator, 0, classFileReader.getConstantPool()); |
| } |
| if (checkMode(mode, SYSTEM)) { |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| } |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| } |
| if (runtimeVisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| } |
| if (runtimeInvisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, 0, mode); |
| } |
| if (length != 0) { |
| for (int i = 0; i < length; i++) { |
| IClassFileAttribute attribute = attributes[i]; |
| if (attribute != innerClassesAttribute |
| && attribute != sourceAttribute |
| && attribute != signatureAttribute |
| && attribute != enclosingMethodAttribute |
| && attribute != runtimeInvisibleAnnotationsAttribute |
| && attribute != runtimeVisibleAnnotationsAttribute |
| && attribute != runtimeInvisibleTypeAnnotationsAttribute |
| && attribute != runtimeVisibleTypeAnnotationsAttribute |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED) |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC) |
| && attribute != bootstrapMethods) { |
| disassemble(attribute, buffer, lineSeparator, 0, mode); |
| } |
| } |
| } |
| } |
| } |
| writeNewLine(buffer, lineSeparator, 0); |
| buffer.append(Messages.disassembler_closetypedeclaration); |
| return buffer.toString(); |
| } |
| |
| private void disassembleGenericSignature(int mode, StringBuffer buffer, final char[] signature) { |
| CharOperation.replace(signature, '/', '.'); |
| final char[][] typeParameters = Signature.getTypeParameters(signature); |
| final int typeParametersLength = typeParameters.length; |
| if (typeParametersLength != 0) { |
| buffer.append('<'); |
| for (int i = 0; i < typeParametersLength; i++) { |
| if (i != 0) { |
| buffer.append(Messages.disassembler_comma); |
| } |
| // extract the name |
| buffer.append(typeParameters[i], 0, CharOperation.indexOf(':', typeParameters[i])); |
| final char[][] bounds = Signature.getTypeParameterBounds(typeParameters[i]); |
| final int boundsLength = bounds.length; |
| if (boundsLength != 0) { |
| if (boundsLength == 1) { |
| final char[] bound = bounds[0]; |
| // check if this is java.lang.Object |
| if (!isJavaLangObject(Signature.toCharArray(bound))) { |
| buffer.append(" extends "); //$NON-NLS-1$ |
| buffer.append(returnClassName(Signature.toCharArray(bound), '.', mode)); |
| } |
| } else { |
| buffer.append(" extends "); //$NON-NLS-1$ |
| for (int j= 0; j < boundsLength; j++) { |
| if (j != 0) { |
| buffer.append(" & "); //$NON-NLS-1$ |
| } |
| buffer.append(returnClassName(Signature.toCharArray(bounds[j]), '.', mode)); |
| } |
| } |
| } |
| } |
| buffer.append('>'); |
| } |
| } |
| |
| private boolean isJavaLangObject(final char[] className) { |
| return CharOperation.equals(TypeConstants.JAVA_LANG_OBJECT, CharOperation.splitOn('.', className)); |
| } |
| |
| |
| private boolean isVarArgs(IMethodInfo methodInfo) { |
| int accessFlags = methodInfo.getAccessFlags(); |
| if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0) return true; |
| // check the presence of the unspecified Varargs attribute |
| return Util.getAttribute(methodInfo, AttributeNamesConstants.VarargsName) != null; |
| } |
| private void disassemble(ICodeAttribute codeAttribute, char[][] parameterNames, char[] methodDescriptor, boolean isStatic, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber - 1); |
| DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, parameterNames, methodDescriptor, isStatic, buffer, lineSeparator, tabNumber, mode); |
| try { |
| codeAttribute.traverse(visitor); |
| } catch(ClassFormatException e) { |
| dumpTab(tabNumber + 3, buffer); |
| buffer.append(Messages.classformat_classformatexception); |
| writeNewLine(buffer, lineSeparator, tabNumber - 1); |
| } |
| final int exceptionTableLength = codeAttribute.getExceptionTableLength(); |
| boolean isFirstAttribute = true; |
| if (exceptionTableLength != 0) { |
| final int tabNumberForExceptionAttribute = tabNumber + 2; |
| isFirstAttribute = false; |
| dumpTab(tabNumberForExceptionAttribute, buffer); |
| final IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable(); |
| buffer.append(Messages.disassembler_exceptiontableheader); |
| writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1); |
| for (int i = 0; i < exceptionTableLength; i++) { |
| if (i != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1); |
| } |
| IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i]; |
| char[] catchType; |
| if (exceptionTableEntry.getCatchTypeIndex() != 0) { |
| catchType = exceptionTableEntry.getCatchType(); |
| CharOperation.replace(catchType, '/', '.'); |
| catchType = returnClassName(catchType, '.', mode); |
| } else { |
| catchType = ANY_EXCEPTION; |
| } |
| buffer.append(Messages.bind(Messages.classfileformat_exceptiontableentry, |
| new String[] { |
| Integer.toString(exceptionTableEntry.getStartPC()), |
| Integer.toString(exceptionTableEntry.getEndPC()), |
| Integer.toString(exceptionTableEntry.getHandlerPC()), |
| new String(catchType), |
| })); |
| } |
| } |
| final ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute(); |
| final int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength(); |
| if (lineAttributeLength != 0) { |
| int tabNumberForLineAttribute = tabNumber + 2; |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute); |
| } else { |
| dumpTab(tabNumberForLineAttribute, buffer); |
| isFirstAttribute = false; |
| } |
| buffer.append(Messages.disassembler_linenumberattributeheader); |
| writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1); |
| int[][] lineattributesEntries = lineNumberAttribute.getLineNumberTable(); |
| for (int i = 0; i < lineAttributeLength; i++) { |
| if (i != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1); |
| } |
| buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry, |
| new String[] { |
| Integer.toString(lineattributesEntries[i][0]), |
| Integer.toString(lineattributesEntries[i][1]) |
| })); |
| } |
| } |
| final ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute(); |
| final int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength(); |
| if (localVariableAttributeLength != 0) { |
| int tabNumberForLocalVariableAttribute = tabNumber + 2; |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute); |
| } else { |
| isFirstAttribute = false; |
| dumpTab(tabNumberForLocalVariableAttribute, buffer); |
| } |
| buffer.append(Messages.disassembler_localvariabletableattributeheader); |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1); |
| ILocalVariableTableEntry[] localVariableTableEntries = localVariableAttribute.getLocalVariableTable(); |
| for (int i = 0; i < localVariableAttributeLength; i++) { |
| if (i != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1); |
| } |
| ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[i]; |
| int index= localVariableTableEntry.getIndex(); |
| int startPC = localVariableTableEntry.getStartPC(); |
| int length = localVariableTableEntry.getLength(); |
| final char[] typeName = Signature.toCharArray(localVariableTableEntry.getDescriptor()); |
| CharOperation.replace(typeName, '/', '.'); |
| buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry, |
| new String[] { |
| Integer.toString(startPC), |
| Integer.toString(startPC + length), |
| new String(localVariableTableEntry.getName()), |
| Integer.toString(index), |
| new String(returnClassName(typeName, '.', mode)) |
| })); |
| } |
| } |
| final ILocalVariableTypeTableAttribute localVariableTypeAttribute= (ILocalVariableTypeTableAttribute) getAttribute(IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE, codeAttribute); |
| final int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength(); |
| if (localVariableTypeTableLength != 0) { |
| int tabNumberForLocalVariableAttribute = tabNumber + 2; |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute); |
| } else { |
| isFirstAttribute = false; |
| dumpTab(tabNumberForLocalVariableAttribute, buffer); |
| } |
| buffer.append(Messages.disassembler_localvariabletypetableattributeheader); |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1); |
| ILocalVariableTypeTableEntry[] localVariableTypeTableEntries = localVariableTypeAttribute.getLocalVariableTypeTable(); |
| for (int i = 0; i < localVariableTypeTableLength; i++) { |
| if (i != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1); |
| } |
| ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[i]; |
| int index= localVariableTypeTableEntry.getIndex(); |
| int startPC = localVariableTypeTableEntry.getStartPC(); |
| int length = localVariableTypeTableEntry.getLength(); |
| final char[] typeName = Signature.toCharArray(localVariableTypeTableEntry.getSignature()); |
| CharOperation.replace(typeName, '/', '.'); |
| buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry, |
| new String[] { |
| Integer.toString(startPC), |
| Integer.toString(startPC + length), |
| new String(localVariableTypeTableEntry.getName()), |
| Integer.toString(index), |
| new String(returnClassName(typeName, '.', mode)) |
| })); |
| } |
| } |
| final int length = codeAttribute.getAttributesCount(); |
| if (length != 0) { |
| IClassFileAttribute[] attributes = codeAttribute.getAttributes(); |
| for (int i = 0; i < length; i++) { |
| IClassFileAttribute attribute = attributes[i]; |
| if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP_TABLE)) { |
| IStackMapTableAttribute stackMapTableAttribute = (IStackMapTableAttribute) attribute; |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| } else { |
| isFirstAttribute = false; |
| dumpTab(tabNumber + 1, buffer); |
| } |
| int numberOfEntries = stackMapTableAttribute.getNumberOfEntries(); |
| buffer.append(Messages.bind(Messages.disassembler_stackmaptableattributeheader, Integer.toString(numberOfEntries))); |
| if (numberOfEntries != 0) { |
| disassemble(stackMapTableAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } else if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP)) { |
| IStackMapAttribute stackMapAttribute = (IStackMapAttribute) attribute; |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| } else { |
| isFirstAttribute = false; |
| dumpTab(tabNumber + 1, buffer); |
| } |
| int numberOfEntries = stackMapAttribute.getNumberOfEntries(); |
| buffer.append(Messages.bind(Messages.disassembler_stackmapattributeheader, Integer.toString(numberOfEntries))); |
| if (numberOfEntries != 0) { |
| disassemble(stackMapAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)) { |
| disassemble((IRuntimeVisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode); |
| } else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)) { |
| disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode); |
| } else if (attribute != lineNumberAttribute |
| && attribute != localVariableAttribute |
| && attribute != localVariableTypeAttribute) { |
| if (!isFirstAttribute) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 2); |
| } else { |
| isFirstAttribute = false; |
| dumpTab(tabNumber + 1, buffer); |
| } |
| buffer.append(Messages.bind(Messages.disassembler_genericattributeheader, |
| new String[] { |
| new String(attribute.getAttributeName()), |
| Long.toString(attribute.getAttributeLength()) |
| })); |
| } |
| } |
| } |
| } |
| |
| private void disassemble(IStackMapTableAttribute attribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| int numberOfEntries = attribute.getNumberOfEntries(); |
| final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame(); |
| int absolutePC = -1; |
| for (int j = 0; j < numberOfEntries; j++) { |
| if (j > 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| } |
| final IStackMapFrame frame = stackMapFrames[j]; |
| // disassemble each frame |
| int type = frame.getFrameType(); |
| int offsetDelta = frame.getOffsetDelta(); |
| if (absolutePC == -1) { |
| absolutePC = offsetDelta; |
| } else { |
| absolutePC += (offsetDelta + 1); |
| } |
| switch(type) { |
| case 247 : // SAME_LOCALS_1_STACK_ITEM_EXTENDED |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_same_locals_1_stack_item_extended, |
| Integer.toString(absolutePC), |
| disassemble(frame.getStackItems(), mode))); |
| break; |
| case 248 : |
| case 249 : |
| case 250: |
| // CHOP |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_chop, |
| Integer.toString(absolutePC), |
| Integer.toString(251 - type))); |
| break; |
| case 251 : |
| // SAME_FRAME_EXTENDED |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_same_frame_extended, |
| Integer.toString(absolutePC))); |
| break; |
| case 252 : |
| case 253 : |
| case 254 : |
| // APPEND |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_append, |
| Integer.toString(absolutePC), |
| disassemble(frame.getLocals(), mode))); |
| break; |
| case 255 : |
| // FULL_FRAME |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_full_frame, |
| new String[] { |
| Integer.toString(absolutePC), |
| Integer.toString(frame.getNumberOfLocals()), |
| disassemble(frame.getLocals(), mode), |
| Integer.toString(frame.getNumberOfStackItems()), |
| disassemble(frame.getStackItems(), mode), |
| dumpNewLineWithTabs(lineSeparator, tabNumber + 5) |
| })); |
| break; |
| default: |
| if (type <= 63) { |
| // SAME_FRAME |
| offsetDelta = type; |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_same_frame, |
| Integer.toString(absolutePC))); |
| } else if (type <= 127) { |
| // SAME_LOCALS_1_STACK_ITEM |
| offsetDelta = type - 64; |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_same_locals_1_stack_item, |
| Integer.toString(absolutePC), |
| disassemble(frame.getStackItems(), mode))); |
| } |
| } |
| } |
| } |
| |
| private void disassemble(IStackMapAttribute attribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| int numberOfEntries = attribute.getNumberOfEntries(); |
| final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame(); |
| for (int j = 0; j < numberOfEntries; j++) { |
| if (j > 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 3); |
| } |
| final IStackMapFrame frame = stackMapFrames[j]; |
| // disassemble each frame |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_frame_full_frame, |
| new String[] { |
| Integer.toString(frame.getOffsetDelta()), |
| Integer.toString(frame.getNumberOfLocals()), |
| disassemble(frame.getLocals(), mode), |
| Integer.toString(frame.getNumberOfStackItems()), |
| disassemble(frame.getStackItems(), mode), |
| dumpNewLineWithTabs(lineSeparator, tabNumber + 5) |
| })); |
| } |
| } |
| |
| private String bootstrapMethodDescription(IBootstrapMethodsEntry entry, IConstantPool constantPool) { |
| // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html |
| // The BootstrapMethods attribute records bootstrap method specifiers referenced by invokedynamic instructions. |
| // The value of the bootstrap_method_ref item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_MethodHandle_info structure (§4.4.8). |
| // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8 |
| // constantpoolentry.getKind() = IConstantPoolConstant.CONSTANT_MethodHandle |
| |
| ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPool.decodeEntry(entry.getBootstrapMethodReference()); |
| |
| // The reference_kind item of the CONSTANT_MethodHandle_info structure should have the value 6 (REF_invokeStatic) or 8 (REF_newInvokeSpecial) |
| // (§5.4.3.5) or else invocation of the bootstrap method handle during call site specifier resolution for an invokedynamic instruction will complete abruptly. |
| // If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 (REF_invokeStatic), 7 (REF_invokeSpecial), |
| // or 9 (REF_invokeInterface), the name of the method represented by a CONSTANT_Methodref_info structure must not be <init> or <clinit>. |
| |
| if (constantPoolEntry2.getReferenceKind() != 6) |
| return null; |
| ConstantPoolEntry constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex()); |
| StringBuilder builder = new StringBuilder(); |
| //String[] methodMsg = methodDescription(constantPoolEntry); |
| builder.append(Messages.bind("invokestatic {0}.{1}:{2}", methodDescription(constantPoolEntry))); //$NON-NLS-1$ |
| return builder.toString(); |
| } |
| |
| private String[] bootstrapArgumentsDescription(IBootstrapMethodsEntry entry, IConstantPool constantPool) { |
| // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 |
| // bootstrap_arguments |
| // Each entry in the bootstrap_arguments array must be a valid index into the constant_pool table. |
| // The constant_pool entry at that index must be a CONSTANT_String_info, CONSTANT_Class_info, CONSTANT_Integer_info |
| // CONSTANT_Long_info, CONSTANT_Float_info, CONSTANT_Double_info, CONSTANT_MethodHandle_info, or |
| // CONSTANT_MethodType_info structure (§4.4.3, §4.4.1, §4.4.4, §4.4.5), §4.4.8, §4.4.9). |
| if (entry.getBootstrapArguments().length == 0) |
| return null; |
| int[] bootstrapArguments = entry.getBootstrapArguments(); |
| String[] arguments = new String[bootstrapArguments.length]; |
| for (int i = 0, length = bootstrapArguments.length; i < length; i++) { |
| ConstantPoolEntry constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(bootstrapArguments[i]); |
| switch(constantPoolEntry.getKind()) { |
| case IConstantPoolConstant.CONSTANT_Integer: |
| arguments[i] = ((Integer) constantPoolEntry.getIntegerValue()).toString(); |
| break; |
| case IConstantPoolConstant.CONSTANT_MethodHandle: |
| // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8 |
| // If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 (REF_invokeStatic), |
| // 7 (REF_invokeSpecial), or 8 (REF_newInvokeSpecial), then the constant_pool entry at that |
| // index must be a CONSTANT_Methodref_info structure (§4.4.2) representing a class's method or |
| // constructor (§2.9) for which a method handle is to be created. |
| ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPoolEntry; |
| StringBuilder builder = new StringBuilder(10); |
| switch(constantPoolEntry2.getReferenceKind()) { |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic: |
| builder.append("invokestatic "); //$NON-NLS-1$ |
| //$FALL-THROUGH$ |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeVirtual: |
| case IConstantPoolConstant.METHOD_TYPE_REF_NewInvokeSpecial: |
| constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex()); |
| builder.append(Messages.bind("{0}.{1}:{2}", methodDescription(constantPoolEntry))); //$NON-NLS-1$ |
| arguments[i] = builder.toString(); |
| break; |
| } |
| break; |
| case IConstantPoolConstant.CONSTANT_MethodType: |
| arguments[i] = new String(((ConstantPoolEntry2) constantPoolEntry).getMethodDescriptor()); |
| break; |
| } |
| } |
| return arguments; |
| } |
| |
| private String[] methodDescription(IConstantPoolEntry constantPoolEntry) { |
| return new String[] { new String(constantPoolEntry.getClassName()), |
| new String(constantPoolEntry.getMethodName()), |
| new String(constantPoolEntry.getMethodDescriptor())}; |
| } |
| |
| private void disassemble(IConstantPool constantPool, StringBuffer buffer, String lineSeparator, int tabNumber) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| int length = constantPool.getConstantPoolCount(); |
| buffer.append(Messages.disassembler_constantpoolheader); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| for (int i = 1; i < length; i++) { |
| if (i != 1) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| } |
| IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(i); |
| String[] methodDescription; |
| switch (constantPool.getEntryKind(i)) { |
| case IConstantPoolConstant.CONSTANT_Class : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_class, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getClassInfoNameIndex()), |
| new String(constantPoolEntry.getClassInfoName())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Double : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_double, |
| new String[] { |
| Integer.toString(i), |
| Double.toString(constantPoolEntry.getDoubleValue())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Fieldref : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_fieldref, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getClassIndex()), |
| Integer.toString(constantPoolEntry.getNameAndTypeIndex()), |
| new String(constantPoolEntry.getClassName()), |
| new String(constantPoolEntry.getFieldName()), |
| new String(constantPoolEntry.getFieldDescriptor()) |
| })); |
| break; |
| case IConstantPoolConstant.CONSTANT_Float : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_float, |
| new String[] { |
| Integer.toString(i), |
| Float.toString(constantPoolEntry.getFloatValue())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Integer : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_integer, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getIntegerValue())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_InterfaceMethodref : |
| methodDescription = methodDescription(constantPoolEntry); |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_interfacemethodref, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getClassIndex()), |
| Integer.toString(constantPoolEntry.getNameAndTypeIndex()), |
| methodDescription[0], methodDescription[1], methodDescription[2]})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Long : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_long, |
| new String[] { |
| Integer.toString(i), |
| Long.toString(constantPoolEntry.getLongValue())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Methodref : |
| methodDescription = methodDescription(constantPoolEntry); |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_methodref, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getClassIndex()), |
| Integer.toString(constantPoolEntry.getNameAndTypeIndex()), |
| methodDescription[0], methodDescription[1], methodDescription[2]})); |
| break; |
| case IConstantPoolConstant.CONSTANT_NameAndType : |
| int nameIndex = constantPoolEntry.getNameAndTypeInfoNameIndex(); |
| int typeIndex = constantPoolEntry.getNameAndTypeInfoDescriptorIndex(); |
| IConstantPoolEntry entry = constantPool.decodeEntry(nameIndex); |
| char[] nameValue = entry.getUtf8Value(); |
| entry = constantPool.decodeEntry(typeIndex); |
| char[] typeValue = entry.getUtf8Value(); |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_name_and_type, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(nameIndex), |
| Integer.toString(typeIndex), |
| String.valueOf(nameValue), |
| String.valueOf(typeValue)})); |
| break; |
| case IConstantPoolConstant.CONSTANT_String : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_string, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(constantPoolEntry.getStringIndex()), |
| decodeStringValue(constantPoolEntry.getStringValue())})); |
| break; |
| case IConstantPoolConstant.CONSTANT_Utf8 : |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_utf8, |
| new String[] { |
| Integer.toString(i), |
| decodeStringValue(new String(constantPoolEntry.getUtf8Value()))})); |
| break; |
| case IConstantPoolConstant.CONSTANT_MethodHandle : |
| IConstantPoolEntry2 entry2 = (IConstantPoolEntry2) constantPoolEntry; |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_methodhandle, |
| new String[] { |
| Integer.toString(i), |
| getReferenceKind(entry2.getReferenceKind()), |
| Integer.toString(entry2.getReferenceIndex()), |
| })); |
| break; |
| case IConstantPoolConstant.CONSTANT_MethodType : |
| entry2 = (IConstantPoolEntry2) constantPoolEntry; |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_methodtype, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(entry2.getDescriptorIndex()), |
| String.valueOf(entry2.getMethodDescriptor()), |
| })); |
| break; |
| case IConstantPoolConstant.CONSTANT_InvokeDynamic : |
| entry2 = (IConstantPoolEntry2) constantPoolEntry; |
| buffer.append( |
| Messages.bind(Messages.disassembler_constantpool_invokedynamic, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(entry2.getBootstrapMethodAttributeIndex()), |
| Integer.toString(entry2.getNameAndTypeIndex()), |
| new String(constantPoolEntry.getMethodName()), |
| new String(constantPoolEntry.getMethodDescriptor()) |
| })); |
| } |
| } |
| } |
| |
| private String getReferenceKind(int referenceKind) { |
| String message = null; |
| switch(referenceKind) { |
| case IConstantPoolConstant.METHOD_TYPE_REF_GetField : |
| message = Messages.disassembler_method_type_ref_getfield; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_GetStatic : |
| message = Messages.disassembler_method_type_ref_getstatic; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_PutField : |
| message = Messages.disassembler_method_type_ref_putfield; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_PutStatic : |
| message = Messages.disassembler_method_type_ref_putstatic; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeInterface : |
| message = Messages.disassembler_method_type_ref_invokeinterface; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeSpecial : |
| message = Messages.disassembler_method_type_ref_invokespecial; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic : |
| message = Messages.disassembler_method_type_ref_invokestatic; |
| break; |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeVirtual : |
| message = Messages.disassembler_method_type_ref_invokevirtual; |
| break; |
| default : |
| message = Messages.disassembler_method_type_ref_newinvokespecial; |
| } |
| return Messages.bind(message, new String[] { Integer.toString(referenceKind) }); |
| } |
| |
| private void disassemble(IEnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_enclosingmethodheader); |
| buffer |
| .append(Messages.disassembler_constantpoolindex) |
| .append(enclosingMethodAttribute.getEnclosingClassIndex()) |
| .append(" ")//$NON-NLS-1$ |
| .append(Messages.disassembler_constantpoolindex) |
| .append(enclosingMethodAttribute.getMethodNameAndTypeIndex()) |
| .append(" ")//$NON-NLS-1$ |
| .append(enclosingMethodAttribute.getEnclosingClass()); |
| if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) { |
| buffer |
| .append(".")//$NON-NLS-1$ |
| .append(enclosingMethodAttribute.getMethodName()) |
| .append(enclosingMethodAttribute.getMethodDescriptor()); |
| } |
| } |
| |
| private void disassembleEnumConstants(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, char[][] argumentTypes, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); |
| // disassemble compact version of annotations |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| buffer.append(new String(fieldInfo.getName())); |
| buffer.append('('); |
| final int length = argumentTypes.length; |
| if (length != 0) { |
| // insert default value for corresponding argument types |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer.append(Messages.disassembler_comma); |
| } |
| final char[] type = argumentTypes[i]; |
| switch(type.length) { |
| case 1 : |
| switch(type[0]) { |
| case 'B' : |
| case 'I' : |
| case 'J' : |
| case 'D' : |
| case 'F' : |
| case 'S' : |
| buffer.append('0'); |
| break; |
| case 'Z' : |
| buffer.append("false"); //$NON-NLS-1$ |
| break; |
| case 'C' : |
| buffer.append("\' \'"); //$NON-NLS-1$ |
| break; |
| } |
| break; |
| default : |
| buffer.append("null"); //$NON-NLS-1$ |
| } |
| } |
| } |
| buffer.append(')').append(Messages.disassembler_comma); |
| } |
| |
| /** |
| * Disassemble a field info |
| */ |
| private void disassemble(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| final char[] fieldDescriptor = fieldInfo.getDescriptor(); |
| final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE); |
| if (checkMode(mode, SYSTEM | DETAILED)) { |
| buffer.append(Messages.bind(Messages.classfileformat_fieldddescriptor, |
| new String[] { |
| Integer.toString(fieldInfo.getDescriptorIndex()), |
| new String(fieldDescriptor) |
| })); |
| if (fieldInfo.isDeprecated()) { |
| buffer.append(Messages.disassembler_deprecated); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| if (signatureAttribute != null) { |
| buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature()))); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } |
| final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); |
| final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); |
| final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); |
| if (checkMode(mode, DETAILED)) { |
| // disassemble compact version of annotations |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| } |
| if (checkMode(mode, WORKING_COPY)) { |
| decodeModifiersForFieldForWorkingCopy(buffer, fieldInfo.getAccessFlags()); |
| if (signatureAttribute != null) { |
| buffer.append(returnClassName(getSignatureForField(signatureAttribute.getSignature()), '.', mode)); |
| } else { |
| buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode)); |
| } |
| } else { |
| decodeModifiersForField(buffer, fieldInfo.getAccessFlags()); |
| if (fieldInfo.isSynthetic()) { |
| buffer.append("synthetic"); //$NON-NLS-1$ |
| buffer.append(Messages.disassembler_space); |
| } |
| buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode)); |
| } |
| buffer.append(' '); |
| buffer.append(new String(fieldInfo.getName())); |
| IConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute(); |
| if (constantValueAttribute != null) { |
| buffer.append(Messages.disassembler_fieldhasconstant); |
| IConstantPoolEntry constantPoolEntry = constantValueAttribute.getConstantValue(); |
| switch(constantPoolEntry.getKind()) { |
| case IConstantPoolConstant.CONSTANT_Long : |
| buffer.append(constantPoolEntry.getLongValue() + "L"); //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Float : |
| buffer.append(constantPoolEntry.getFloatValue() + "f"); //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Double : |
| final double doubleValue = constantPoolEntry.getDoubleValue(); |
| if (checkMode(mode, ClassFileBytesDisassembler.WORKING_COPY)) { |
| if (doubleValue == Double.POSITIVE_INFINITY) { |
| buffer.append("1.0 / 0.0"); //$NON-NLS-1$ |
| } else if (doubleValue == Double.NEGATIVE_INFINITY) { |
| buffer.append("-1.0 / 0.0"); //$NON-NLS-1$ |
| } else { |
| buffer.append(constantPoolEntry.getDoubleValue()); |
| } |
| } else { |
| buffer.append(constantPoolEntry.getDoubleValue()); |
| } |
| break; |
| case IConstantPoolConstant.CONSTANT_Integer: |
| switch(fieldDescriptor[0]) { |
| case 'C' : |
| buffer.append("'" + (char) constantPoolEntry.getIntegerValue() + "'"); //$NON-NLS-1$//$NON-NLS-2$ |
| break; |
| case 'Z' : |
| buffer.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$ |
| break; |
| case 'B' : |
| buffer.append(constantPoolEntry.getIntegerValue()); |
| break; |
| case 'S' : |
| buffer.append(constantPoolEntry.getIntegerValue()); |
| break; |
| case 'I' : |
| buffer.append(constantPoolEntry.getIntegerValue()); |
| } |
| break; |
| case IConstantPoolConstant.CONSTANT_String: |
| buffer.append("\"" + decodeStringValue(constantPoolEntry.getStringValue()) + "\"" );//$NON-NLS-1$//$NON-NLS-2$ |
| } |
| } |
| buffer.append(Messages.disassembler_endoffieldheader); |
| if (checkMode(mode, SYSTEM)) { |
| IClassFileAttribute[] attributes = fieldInfo.getAttributes(); |
| int length = attributes.length; |
| if (length != 0) { |
| for (int i = 0; i < length; i++) { |
| IClassFileAttribute attribute = attributes[i]; |
| if (attribute != constantValueAttribute |
| && attribute != signatureAttribute |
| && attribute != runtimeInvisibleAnnotationsAttribute |
| && attribute != runtimeVisibleAnnotationsAttribute |
| && attribute != runtimeInvisibleTypeAnnotationsAttribute |
| && attribute != runtimeVisibleTypeAnnotationsAttribute |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED) |
| && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) { |
| disassemble(attribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| } |
| if (runtimeVisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeInvisibleAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeVisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| if (runtimeInvisibleTypeAnnotationsAttribute != null) { |
| disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| } |
| |
| private void disassemble(IInnerClassesAttribute innerClassesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| buffer.append(Messages.disassembler_innerattributesheader); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| IInnerClassesAttributeEntry[] innerClassesAttributeEntries = innerClassesAttribute.getInnerClassAttributesEntries(); |
| int length = innerClassesAttributeEntries.length; |
| int innerClassNameIndex, outerClassNameIndex, innerNameIndex, accessFlags; |
| IInnerClassesAttributeEntry innerClassesAttributeEntry; |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer.append(Messages.disassembler_comma); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| } |
| innerClassesAttributeEntry = innerClassesAttributeEntries[i]; |
| innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex(); |
| outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex(); |
| innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex(); |
| accessFlags = innerClassesAttributeEntry.getAccessFlags(); |
| buffer |
| .append(Messages.disassembler_openinnerclassentry) |
| .append(Messages.disassembler_inner_class_info_name) |
| .append(Messages.disassembler_constantpoolindex) |
| .append(innerClassNameIndex); |
| if (innerClassNameIndex != 0) { |
| buffer |
| .append(Messages.disassembler_space) |
| .append(innerClassesAttributeEntry.getInnerClassName()); |
| } |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space) |
| .append(Messages.disassembler_outer_class_info_name) |
| .append(Messages.disassembler_constantpoolindex) |
| .append(outerClassNameIndex); |
| if (outerClassNameIndex != 0) { |
| buffer |
| .append(Messages.disassembler_space) |
| .append(innerClassesAttributeEntry.getOuterClassName()); |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| dumpTab(tabNumber, buffer); |
| buffer.append(Messages.disassembler_space); |
| buffer |
| .append(Messages.disassembler_inner_name) |
| .append(Messages.disassembler_constantpoolindex) |
| .append(innerNameIndex); |
| if (innerNameIndex != 0) { |
| buffer |
| .append(Messages.disassembler_space) |
| .append(innerClassesAttributeEntry.getInnerName()); |
| } |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space) |
| .append(Messages.disassembler_inner_accessflags) |
| .append(accessFlags) |
| .append(Messages.disassembler_space); |
| decodeModifiersForInnerClasses(buffer, accessFlags, true); |
| buffer |
| .append(Messages.disassembler_closeinnerclassentry); |
| } |
| } |
| |
| private void disassemble(IBootstrapMethodsAttribute bootstrapMethodsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, IConstantPool constantPool) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| buffer.append(Messages.disassembler_bootstrapmethodattributesheader); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| IBootstrapMethodsEntry[] entries = bootstrapMethodsAttribute.getBootstrapMethods(); |
| int length = entries.length; |
| for (int i = 0; i < length; i++) { |
| if (i != 0) { |
| buffer.append(Messages.disassembler_comma); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| } |
| IBootstrapMethodsEntry entry = entries[i]; |
| String[] argumentsName = bootstrapArgumentsDescription(entry, constantPool); |
| |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_bootstrapmethodentry, |
| new String[] { |
| Integer.toString(i), |
| Integer.toString(entry.getBootstrapMethodReference()), |
| bootstrapMethodDescription(entry, constantPool), |
| getArguments(entry.getBootstrapArguments(), argumentsName) |
| })); |
| } |
| } |
| |
| private String getArguments(int[] arguments, String[] argumentsName) { |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, max = arguments.length; i < max; i++) { |
| buffer.append( |
| Messages.bind( |
| Messages.disassembler_bootstrapmethodentry_argument, |
| new String[] { |
| Integer.toString(arguments[i]), |
| argumentsName[i] |
| })); |
| if (i != arguments.length - 1) |
| buffer.append("\n\t\t"); //$NON-NLS-1$ |
| } |
| return String.valueOf(buffer); |
| } |
| private void disassemble(int index, IParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| IAnnotation[] annotations = parameterAnnotation.getAnnotations(); |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append( |
| Messages.bind(Messages.disassembler_parameterannotationentrystart, new String[] {Integer.toString(index), Integer.toString(annotations.length)})); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimeinvisibleannotationsattributeheader); |
| IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations(); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimeinvisibleparameterannotationsattributeheader); |
| IParameterAnnotation[] parameterAnnotations = runtimeInvisibleParameterAnnotationsAttribute.getParameterAnnotations(); |
| for (int i = 0, max = parameterAnnotations.length; i < max; i++) { |
| disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimeinvisibletypeannotationsattributeheader); |
| IExtendedAnnotation[] extendedAnnotations = runtimeInvisibleTypeAnnotationsAttribute.getExtendedAnnotations(); |
| for (int i = 0, max = extendedAnnotations.length; i < max; i++) { |
| disassemble(extendedAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimevisibleannotationsattributeheader); |
| IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations(); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| disassemble(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimevisibleparameterannotationsattributeheader); |
| IParameterAnnotation[] parameterAnnotations = runtimeVisibleParameterAnnotationsAttribute.getParameterAnnotations(); |
| for (int i = 0, max = parameterAnnotations.length; i < max; i++) { |
| disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassemble(IRuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| writeNewLine(buffer, lineSeparator, tabNumber + 1); |
| buffer.append(Messages.disassembler_runtimevisibletypeannotationsattributeheader); |
| IExtendedAnnotation[] extendedAnnotations = runtimeVisibleTypeAnnotationsAttribute.getExtendedAnnotations(); |
| for (int i = 0, max = extendedAnnotations.length; i < max; i++) { |
| disassemble(extendedAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private String disassemble(IVerificationTypeInfo[] infos, int mode) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append('{'); |
| for (int i = 0, max = infos.length; i < max; i++) { |
| if(i != 0) { |
| buffer |
| .append(Messages.disassembler_comma) |
| .append(Messages.disassembler_space); |
| } |
| switch(infos[i].getTag()) { |
| case IVerificationTypeInfo.ITEM_DOUBLE : |
| buffer.append("double"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_FLOAT : |
| buffer.append("float"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_INTEGER : |
| buffer.append("int"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_LONG : |
| buffer.append("long"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_NULL : |
| buffer.append("null"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_OBJECT : |
| char[] classTypeName = infos[i].getClassTypeName(); |
| CharOperation.replace(classTypeName, '/', '.'); |
| if (classTypeName.length > 0 && classTypeName[0] == '[') { // length check for resilience |
| classTypeName = Signature.toCharArray(classTypeName); |
| } |
| buffer.append(returnClassName(classTypeName, '.', mode)); |
| break; |
| case IVerificationTypeInfo.ITEM_TOP : |
| buffer.append("_"); //$NON-NLS-1$ |
| break; |
| case IVerificationTypeInfo.ITEM_UNINITIALIZED : |
| buffer.append("uninitialized("); //$NON-NLS-1$ |
| buffer.append(infos[i].getOffset()); |
| buffer.append(')'); |
| break; |
| case IVerificationTypeInfo.ITEM_UNINITIALIZED_THIS : |
| buffer.append("uninitialized_this"); //$NON-NLS-1$ |
| } |
| } |
| buffer.append('}'); |
| return String.valueOf(buffer); |
| } |
| |
| private void disassembleAsModifier(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.'); |
| buffer.append('@').append(returnClassName(Signature.toCharArray(typeName), '.', mode)); |
| final IAnnotationComponent[] components = annotation.getComponents(); |
| final int length = components.length; |
| if (length != 0) { |
| buffer.append('('); |
| for (int i = 0; i < length; i++) { |
| if (i > 0) { |
| buffer.append(','); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| buffer.append(')'); |
| } |
| } |
| |
| private void disassembleAsModifier(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| buffer.append(annotationComponent.getComponentName()).append('='); |
| disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| |
| private void disassembleAsModifier(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| switch(annotationComponentValue.getTag()) { |
| case IAnnotationComponentValue.BYTE_TAG: |
| case IAnnotationComponentValue.CHAR_TAG: |
| case IAnnotationComponentValue.DOUBLE_TAG: |
| case IAnnotationComponentValue.FLOAT_TAG: |
| case IAnnotationComponentValue.INTEGER_TAG: |
| case IAnnotationComponentValue.LONG_TAG: |
| case IAnnotationComponentValue.SHORT_TAG: |
| case IAnnotationComponentValue.BOOLEAN_TAG: |
| case IAnnotationComponentValue.STRING_TAG: |
| IConstantPoolEntry constantPoolEntry = annotationComponentValue.getConstantValue(); |
| String value = null; |
| switch(constantPoolEntry.getKind()) { |
| case IConstantPoolConstant.CONSTANT_Long : |
| value = constantPoolEntry.getLongValue() + "L"; //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Float : |
| value = constantPoolEntry.getFloatValue() + "f"; //$NON-NLS-1$ |
| break; |
| case IConstantPoolConstant.CONSTANT_Double : |
| value = Double.toString(constantPoolEntry.getDoubleValue()); |
| break; |
| case IConstantPoolConstant.CONSTANT_Integer: |
| StringBuffer temp = new StringBuffer(); |
| switch(annotationComponentValue.getTag()) { |
| case IAnnotationComponentValue.CHAR_TAG : |
| temp.append('\''); |
| escapeChar(temp, (char) constantPoolEntry.getIntegerValue()); |
| temp.append('\''); |
| break; |
| case IAnnotationComponentValue.BOOLEAN_TAG : |
| temp.append(constantPoolEntry.getIntegerValue() == 1 ? "true" : "false");//$NON-NLS-1$//$NON-NLS-2$ |
| break; |
| case IAnnotationComponentValue.BYTE_TAG : |
| temp.append("(byte) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| break; |
| case IAnnotationComponentValue.SHORT_TAG : |
| temp.append("(short) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| break; |
| case IAnnotationComponentValue.INTEGER_TAG : |
| temp.append("(int) ").append(constantPoolEntry.getIntegerValue()); //$NON-NLS-1$ |
| } |
| value = String.valueOf(temp); |
| break; |
| case IConstantPoolConstant.CONSTANT_Utf8: |
| value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$ |
| } |
| buffer.append(value); |
| break; |
| case IAnnotationComponentValue.ENUM_TAG: |
| final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.'); |
| final char[] constantName = annotationComponentValue.getEnumConstantName(); |
| buffer.append(returnClassName(Signature.toCharArray(typeName), '.', mode)).append('.').append(constantName); |
| break; |
| case IAnnotationComponentValue.CLASS_TAG: |
| constantPoolEntry = annotationComponentValue.getClassInfo(); |
| final char[] className = CharOperation.replaceOnCopy(constantPoolEntry.getUtf8Value(), '/', '.'); |
| buffer.append(returnClassName(Signature.toCharArray(className), '.', mode)); |
| break; |
| case IAnnotationComponentValue.ANNOTATION_TAG: |
| IAnnotation annotation = annotationComponentValue.getAnnotationValue(); |
| disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode); |
| break; |
| case IAnnotationComponentValue.ARRAY_TAG: |
| final IAnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues(); |
| buffer.append('{'); |
| for (int i = 0, max = annotationComponentValues.length; i < max; i++) { |
| if (i > 0) { |
| buffer.append(','); |
| } |
| disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| buffer.append('}'); |
| } |
| } |
| |
| private void disassembleAsModifier(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue(); |
| disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| |
| private void disassembleAsModifier(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations(); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassembleAsModifier(IParameterAnnotation[] parameterAnnotations, StringBuffer buffer, int index, String lineSeparator, int tabNumber, int mode) { |
| if (parameterAnnotations.length > index) { |
| disassembleAsModifier(parameterAnnotations[index], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassembleAsModifier(IParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| if (parameterAnnotation == null) return; |
| IAnnotation[] annotations = parameterAnnotation.getAnnotations(); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| if (i > 0) { |
| buffer.append(' '); |
| } |
| disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassembleAsModifier(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { |
| IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations(); |
| for (int i = 0, max = annotations.length; i < max; i++) { |
| if (i > 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| } |
| disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode); |
| } |
| } |
| |
| private void disassembleTypeMembers(IClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum) { |
| IFieldInfo[] fields = classFileReader.getFieldInfos(); |
| if (isEnum && checkMode(mode, WORKING_COPY)) { |
| int index = 0; |
| final int fieldsLength = fields.length; |
| IMethodInfo[] methods = classFileReader.getMethodInfos(); |
| char[][] constructorArguments = getConstructorArgumentsForEnum(methods); |
| enumConstantLoop: for (; index < fieldsLength; index++) { |
| final IFieldInfo fieldInfo = fields[index]; |
| final int accessFlags = fieldInfo.getAccessFlags(); |
| if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassembleEnumConstants(fields[index], buffer, lineSeparator, tabNumber, constructorArguments, mode); |
| } else { |
| break enumConstantLoop; |
| } |
| } |
| buffer.append(';'); |
| boolean foundSyntheticField = false; |
| fieldLoop: for (; index < fieldsLength; index++) { |
| if (!foundSyntheticField && CharOperation.equals(TypeConstants.SYNTHETIC_ENUM_VALUES, fields[index].getName())) { |
| foundSyntheticField = true; |
| continue fieldLoop; |
| } |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassemble(fields[index], buffer, lineSeparator, tabNumber, mode); |
| } |
| methodLoop: for (int i = 0, max = methods.length; i < max; i++) { |
| final IMethodInfo methodInfo = methods[i]; |
| if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUES)) { |
| final char[] descriptor = methodInfo.getDescriptor(); |
| CharOperation.replace(descriptor, '/', '.'); |
| if (Signature.getParameterCount(descriptor) == 0) { |
| if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode), |
| CharOperation.concat(new char[] {'[', 'L'}, className, new char[] {';'}))) { |
| continue methodLoop; |
| } |
| } |
| } else if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUEOF)) { |
| final char[] descriptor = methodInfo.getDescriptor(); |
| CharOperation.replace(descriptor, '/', '.'); |
| final char[][] parameterTypes = Signature.getParameterTypes(descriptor); |
| if (parameterTypes.length == 1 |
| && CharOperation.equals(parameterTypes[0], "Ljava.lang.String;".toCharArray())) { //$NON-NLS-1$ |
| if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode), |
| CharOperation.concat('L', className, ';'))) { |
| continue methodLoop; |
| } |
| } |
| } else if (methodInfo.isClinit() || methodInfo.isSynthetic()) { |
| continue methodLoop; |
| } else if (methodInfo.isConstructor()) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassembleEnumConstructor(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode); |
| } else { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassemble(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| } else { |
| for (int i = 0, max = fields.length; i < max; i++) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassemble(fields[i], buffer, lineSeparator, tabNumber, mode); |
| } |
| IMethodInfo[] methods = classFileReader.getMethodInfos(); |
| for (int i = 0, max = methods.length; i < max; i++) { |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| disassemble(classFileReader, className, methods[i], buffer, lineSeparator, tabNumber, mode); |
| } |
| } |
| } |
| |
| private char[][] getConstructorArgumentsForEnum(final IMethodInfo[] methods) { |
| loop: for (int i = 0, max = methods.length; i < max; i++) { |
| IMethodInfo methodInfo = methods[i]; |
| if (methodInfo.isConstructor()) { |
| char[][] parameterTypes = Signature.getParameterTypes(methodInfo.getDescriptor()); |
| final int length = parameterTypes.length; |
| if (length >= 2) { |
| return CharOperation.subarray(parameterTypes, 2, length); |
| } |
| } else { |
| continue loop; |
| } |
| } |
| return null; |
| } |
| |
| private final void dumpTab(int tabNumber, StringBuffer buffer) { |
| for (int i = 0; i < tabNumber; i++) { |
| buffer.append(Messages.disassembler_indentation); |
| } |
| } |
| |
| private final String dumpNewLineWithTabs(String lineSeparator, int tabNumber) { |
| StringBuffer buffer = new StringBuffer(); |
| writeNewLine(buffer, lineSeparator, tabNumber); |
| return String.valueOf(buffer); |
| } |
| |
| /** |
| * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#getDescription() |
| */ |
| public String getDescription() { |
| return Messages.disassembler_description; |
| } |
| |
| private IEnclosingMethodAttribute getEnclosingMethodAttribute(IClassFileReader classFileReader) { |
| IClassFileAttribute[] attributes = classFileReader.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.ENCLOSING_METHOD)) { |
| return (IEnclosingMethodAttribute) attributes[i]; |
| } |
| } |
| return null; |
| } |
| private IClassFileAttribute getAttribute(final char[] attributeName, final ICodeAttribute codeAttribute) { |
| IClassFileAttribute[] attributes = codeAttribute.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) { |
| return attributes[i]; |
| } |
| } |
| return null; |
| } |
| |
| private char[][] getParameterNames(char[] methodDescriptor, ICodeAttribute codeAttribute, IMethodParametersAttribute parametersAttribute, int accessFlags) { |
| int paramCount = Signature.getParameterCount(methodDescriptor); |
| char[][] parameterNames = new char[paramCount][]; |
| // check if the code attribute has debug info for this method |
| if (parametersAttribute != null) { |
| int parameterCount = parametersAttribute.getMethodParameterLength(); |
| for (int i = 0; i < paramCount; i++) { |
| if (i < parameterCount && parametersAttribute.getParameterName(i) != null) { |
| parameterNames[i] = parametersAttribute.getParameterName(i); |
| } else { |
| parameterNames[i] = Messages.disassembler_anonymousparametername.toCharArray(); |
| } |
| } |
| } else if (codeAttribute != null) { |
| ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute(); |
| if (localVariableAttribute != null) { |
| ILocalVariableTableEntry[] entries = localVariableAttribute.getLocalVariableTable(); |
| final int startingIndex = (accessFlags & IModifierConstants.ACC_STATIC) != 0 ? 0 : 1; |
| for (int i = 0; i < paramCount; i++) { |
| ILocalVariableTableEntry searchedEntry = getEntryFor(getLocalIndex(startingIndex, i, methodDescriptor), entries); |
| if (searchedEntry != null) { |
| parameterNames[i] = searchedEntry.getName(); |
| } else { |
| parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); |
| } |
| } |
| } else { |
| for (int i = 0; i < paramCount; i++) { |
| parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); |
| } |
| } |
| } else { |
| for (int i = 0; i < paramCount; i++) { |
| parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); |
| } |
| } |
| return parameterNames; |
| } |
| |
| private int getLocalIndex(final int startingSlot, final int index, final char[] methodDescriptor) { |
| int slot = startingSlot; |
| final char[][] types = Signature.getParameterTypes(methodDescriptor); |
| for (int i = 0; i < index; i++) { |
| final char[] type = types[i]; |
| switch(type.length) { |
| case 1 : |
| switch(type[0]) { |
| case 'D' : |
| case 'J' : |
| slot += 2; |
| break; |
| default : |
| slot++; |
| } |
| break; |
| default : |
| slot++; |
| } |
| } |
| return slot; |
| } |
| |
| private ILocalVariableTableEntry getEntryFor(final int index, final ILocalVariableTableEntry[] entries) { |
| for (int i = 0, max = entries.length; i < max; i++) { |
| ILocalVariableTableEntry entry = entries[i]; |
| if (index == entry.getIndex()) { |
| return entry; |
| } |
| } |
| return null; |
| } |
| |
| private char[] getSignatureForField(char[] fieldDescriptor) { |
| char[] newFieldDescriptor = CharOperation.replaceOnCopy(fieldDescriptor, '/', '.'); |
| newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '%'); |
| char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor); |
| CharOperation.replace(fieldDescriptorSignature, '%', '$'); |
| return fieldDescriptorSignature; |
| } |
| |
| private boolean isDeprecated(IClassFileReader classFileReader) { |
| IClassFileAttribute[] attributes = classFileReader.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.DEPRECATED)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean isSynthetic(IClassFileReader classFileReader) { |
| int flags = classFileReader.getAccessFlags(); |
| if ((flags & IModifierConstants.ACC_SYNTHETIC) != 0) { |
| return true; |
| } |
| IClassFileAttribute[] attributes = classFileReader.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean checkMode(int mode, int flag) { |
| return (mode & flag) != 0; |
| } |
| |
| private boolean isCompact(int mode) { |
| return (mode & ClassFileBytesDisassembler.COMPACT) != 0; |
| } |
| |
| private char[] returnClassName(char[] classInfoName, char separator, int mode) { |
| if (classInfoName.length == 0) { |
| return CharOperation.NO_CHAR; |
| } else if (isCompact(mode)) { |
| int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName); |
| if (lastIndexOfSlash != -1) { |
| return CharOperation.subarray(classInfoName, lastIndexOfSlash + 1, classInfoName.length); |
| } |
| } |
| return classInfoName; |
| } |
| |
| private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) { |
| buffer.append(lineSeparator); |
| dumpTab(tabNumber, buffer); |
| } |
| |
| private String toTypePathString(int[][] typepath) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append('['); |
| for (int i = 0, max = typepath.length; i < max; i++) { |
| int[] typepathElement = typepath[i]; |
| if (i > 0) { |
| buffer.append(',').append(' '); |
| } |
| switch (typepathElement[0]) { |
| case IExtendedAnnotationConstants.TYPE_PATH_DEEPER_IN_ARRAY: |
| buffer.append(Messages.disassembler_extendedannotation_typepath_array); |
| break; |
| case IExtendedAnnotationConstants.TYPE_PATH_DEEPER_IN_INNER_TYPE: |
| buffer.append(Messages.disassembler_extendedannotation_typepath_innertype); |
| break; |
| case IExtendedAnnotationConstants.TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND: |
| buffer.append(Messages.disassembler_extendedannotation_typepath_wildcard); |
| break; |
| case IExtendedAnnotationConstants.TYPE_PATH_TYPE_ARGUMENT_INDEX: |
| buffer.append( |
| Messages.bind(Messages.disassembler_extendedannotation_typepath_typeargument, |
| new String[] { |
| Integer.toString(typepathElement[1]) |
| })); |
| break; |
| default: |
| throw new IllegalStateException("Unrecognized type_path_kind: "+typepathElement[0]); //$NON-NLS-1$ |
| } |
| } |
| buffer.append(']'); |
| return String.valueOf(buffer); |
| } |
| |
| } |