Checkstyle updates from ASM master

Issue: SPR-17267
This commit is contained in:
Juergen Hoeller 2018-09-17 19:09:07 +02:00
parent c385a1de83
commit 69e8bcdf40
14 changed files with 520 additions and 469 deletions

View File

@ -239,6 +239,7 @@ public class ByteVector {
* @param stringValue a String whose UTF8 encoded length must be less than 65536. * @param stringValue a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector. * @return this byte vector.
*/ */
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public ByteVector putUTF8(final String stringValue) { public ByteVector putUTF8(final String stringValue) {
int charLength = stringValue.length(); int charLength = stringValue.length();
if (charLength > 65535) { if (charLength > 65535) {
@ -261,7 +262,7 @@ public class ByteVector {
currentData[currentLength++] = (byte) charValue; currentData[currentLength++] = (byte) charValue;
} else { } else {
length = currentLength; length = currentLength;
return encodeUTF8(stringValue, i, 65535); return encodeUtf8(stringValue, i, 65535);
} }
} }
length = currentLength; length = currentLength;
@ -280,14 +281,14 @@ public class ByteVector {
* encoded characters. * encoded characters.
* @return this byte vector. * @return this byte vector.
*/ */
final ByteVector encodeUTF8(final String stringValue, final int offset, final int maxByteLength) { final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
int charLength = stringValue.length(); int charLength = stringValue.length();
int byteLength = offset; int byteLength = offset;
for (int i = offset; i < charLength; ++i) { for (int i = offset; i < charLength; ++i) {
char charValue = stringValue.charAt(i); char charValue = stringValue.charAt(i);
if (charValue >= '\u0001' && charValue <= '\u007F') { if (charValue >= 0x0001 && charValue <= 0x007F) {
byteLength++; byteLength++;
} else if (charValue <= '\u07FF') { } else if (charValue <= 0x07FF) {
byteLength += 2; byteLength += 2;
} else { } else {
byteLength += 3; byteLength += 3;
@ -308,9 +309,9 @@ public class ByteVector {
int currentLength = length; int currentLength = length;
for (int i = offset; i < charLength; ++i) { for (int i = offset; i < charLength; ++i) {
char charValue = stringValue.charAt(i); char charValue = stringValue.charAt(i);
if (charValue >= '\u0001' && charValue <= '\u007F') { if (charValue >= 0x0001 && charValue <= 0x007F) {
data[currentLength++] = (byte) charValue; data[currentLength++] = (byte) charValue;
} else if (charValue <= '\u07FF') { } else if (charValue <= 0x07FF) {
data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F); data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
data[currentLength++] = (byte) (0x80 | charValue & 0x3F); data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
} else { } else {

View File

@ -99,6 +99,7 @@ public class ClassReader {
* necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct
* ClassFile element offsets within this byte array. * ClassFile element offsets within this byte array.
*/ */
// DontCheck(MemberName): can't be renamed (for backward binary compatibility).
public final byte[] b; public final byte[] b;
/** /**
@ -488,7 +489,7 @@ public class ClassReader {
accessFlags |= Opcodes.ACC_SYNTHETIC; accessFlags |= Opcodes.ACC_SYNTHETIC;
} else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
sourceDebugExtension = sourceDebugExtension =
readUTF(currentAttributeOffset, attributeLength, new char[attributeLength]); readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
} else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
runtimeInvisibleAnnotationsOffset = currentAttributeOffset; runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
} else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
@ -530,7 +531,8 @@ public class ClassReader {
// Visit the Module, ModulePackages and ModuleMainClass attributes. // Visit the Module, ModulePackages and ModuleMainClass attributes.
if (moduleOffset != 0) { if (moduleOffset != 0) {
readModule(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); readModuleAttributes(
classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
} }
// Visit the NestHost attribute. // Visit the NestHost attribute.
@ -685,7 +687,7 @@ public class ClassReader {
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
/** /**
* Reads the module attribute and visit it. * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them.
* *
* @param classVisitor the current class visitor * @param classVisitor the current class visitor
* @param context information about the class being parsed. * @param context information about the class being parsed.
@ -695,7 +697,7 @@ public class ClassReader {
* attribute_info's attribute_name_index and attribute_length fields), or 0. * attribute_info's attribute_name_index and attribute_length fields), or 0.
* @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null. * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null.
*/ */
private void readModule( private void readModuleAttributes(
final ClassVisitor classVisitor, final ClassVisitor classVisitor,
final Context context, final Context context,
final int moduleOffset, final int moduleOffset,
@ -1111,7 +1113,7 @@ public class ClassReader {
context.currentMethodAccessFlags, context.currentMethodAccessFlags,
context.currentMethodName, context.currentMethodName,
context.currentMethodDescriptor, context.currentMethodDescriptor,
signatureIndex == 0 ? null : readUTF(signatureIndex, charBuffer), signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer),
exceptions); exceptions);
if (methodVisitor == null) { if (methodVisitor == null) {
return currentOffset; return currentOffset;
@ -1601,18 +1603,15 @@ public class ClassReader {
// Read the 'exception_table_length' and 'exception_table' field to create a label for each // Read the 'exception_table_length' and 'exception_table' field to create a label for each
// referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks.
{ int exceptionTableLength = readUnsignedShort(currentOffset);
int exceptionTableLength = readUnsignedShort(currentOffset); currentOffset += 2;
currentOffset += 2; while (exceptionTableLength-- > 0) {
while (exceptionTableLength-- > 0) { Label start = createLabel(readUnsignedShort(currentOffset), labels);
Label start = createLabel(readUnsignedShort(currentOffset), labels); Label end = createLabel(readUnsignedShort(currentOffset + 2), labels);
Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels);
Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer);
String catchType = currentOffset += 8;
readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); methodVisitor.visitTryCatchBlock(start, end, handler, catchType);
currentOffset += 8;
methodVisitor.visitTryCatchBlock(start, end, handler, catchType);
}
} }
// Read the Code attributes to create a label for each referenced instruction (the variables // Read the Code attributes to create a label for each referenced instruction (the variables
@ -2142,11 +2141,11 @@ public class ClassReader {
currentOffset += 4 - (currentBytecodeOffset & 3); currentOffset += 4 - (currentBytecodeOffset & 3);
// Read the instruction. // Read the instruction.
Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)];
int nPairs = readInt(currentOffset + 4); int numPairs = readInt(currentOffset + 4);
currentOffset += 8; currentOffset += 8;
int[] keys = new int[nPairs]; int[] keys = new int[numPairs];
Label[] values = new Label[nPairs]; Label[] values = new Label[numPairs];
for (int i = 0; i < nPairs; ++i) { for (int i = 0; i < numPairs; ++i) {
keys[i] = readInt(currentOffset); keys[i] = readInt(currentOffset);
values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)];
currentOffset += 8; currentOffset += 8;
@ -2958,12 +2957,12 @@ public class ClassReader {
private void computeImplicitFrame(final Context context) { private void computeImplicitFrame(final Context context) {
String methodDescriptor = context.currentMethodDescriptor; String methodDescriptor = context.currentMethodDescriptor;
Object[] locals = context.currentFrameLocalTypes; Object[] locals = context.currentFrameLocalTypes;
int nLocal = 0; int numLocal = 0;
if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) {
if ("<init>".equals(context.currentMethodName)) { if ("<init>".equals(context.currentMethodName)) {
locals[nLocal++] = Opcodes.UNINITIALIZED_THIS; locals[numLocal++] = Opcodes.UNINITIALIZED_THIS;
} else { } else {
locals[nLocal++] = readClass(header + 2, context.charBuffer); locals[numLocal++] = readClass(header + 2, context.charBuffer);
} }
} }
// Parse the method descriptor, one argument type descriptor at each iteration. Start by // Parse the method descriptor, one argument type descriptor at each iteration. Start by
@ -2977,16 +2976,16 @@ public class ClassReader {
case 'B': case 'B':
case 'S': case 'S':
case 'I': case 'I':
locals[nLocal++] = Opcodes.INTEGER; locals[numLocal++] = Opcodes.INTEGER;
break; break;
case 'F': case 'F':
locals[nLocal++] = Opcodes.FLOAT; locals[numLocal++] = Opcodes.FLOAT;
break; break;
case 'J': case 'J':
locals[nLocal++] = Opcodes.LONG; locals[numLocal++] = Opcodes.LONG;
break; break;
case 'D': case 'D':
locals[nLocal++] = Opcodes.DOUBLE; locals[numLocal++] = Opcodes.DOUBLE;
break; break;
case '[': case '[':
while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') {
@ -2998,7 +2997,7 @@ public class ClassReader {
++currentMethodDescritorOffset; ++currentMethodDescritorOffset;
} }
} }
locals[nLocal++] = locals[numLocal++] =
methodDescriptor.substring( methodDescriptor.substring(
currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset);
break; break;
@ -3006,12 +3005,12 @@ public class ClassReader {
while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') {
++currentMethodDescritorOffset; ++currentMethodDescritorOffset;
} }
locals[nLocal++] = locals[numLocal++] =
methodDescriptor.substring( methodDescriptor.substring(
currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++);
break; break;
default: default:
context.currentFrameLocalCount = nLocal; context.currentFrameLocalCount = numLocal;
return; return;
} }
} }
@ -3178,7 +3177,11 @@ public class ClassReader {
// Methods to parse attributes // Methods to parse attributes
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
/** @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry. */ /**
* Returns the offset in {@link #b} of the first ClassFile's 'attributes' array field entry.
*
* @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry.
*/
final int getFirstAttributeOffset() { final int getFirstAttributeOffset() {
// Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes
// each), as well as the interfaces array field (2 bytes per interface). // each), as well as the interfaces array field (2 bytes per interface).
@ -3399,12 +3402,13 @@ public class ClassReader {
* large. It is not automatically resized. * large. It is not automatically resized.
* @return the String corresponding to the specified CONSTANT_Utf8 entry. * @return the String corresponding to the specified CONSTANT_Utf8 entry.
*/ */
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public String readUTF8(final int offset, final char[] charBuffer) { public String readUTF8(final int offset, final char[] charBuffer) {
int constantPoolEntryIndex = readUnsignedShort(offset); int constantPoolEntryIndex = readUnsignedShort(offset);
if (offset == 0 || constantPoolEntryIndex == 0) { if (offset == 0 || constantPoolEntryIndex == 0) {
return null; return null;
} }
return readUTF(constantPoolEntryIndex, charBuffer); return readUtf(constantPoolEntryIndex, charBuffer);
} }
/** /**
@ -3416,14 +3420,14 @@ public class ClassReader {
* large. It is not automatically resized. * large. It is not automatically resized.
* @return the String corresponding to the specified CONSTANT_Utf8 entry. * @return the String corresponding to the specified CONSTANT_Utf8 entry.
*/ */
final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) { final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) {
String value = constantUtf8Values[constantPoolEntryIndex]; String value = constantUtf8Values[constantPoolEntryIndex];
if (value != null) { if (value != null) {
return value; return value;
} }
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
return constantUtf8Values[constantPoolEntryIndex] = return constantUtf8Values[constantPoolEntryIndex] =
readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
} }
/** /**
@ -3435,7 +3439,7 @@ public class ClassReader {
* large. It is not automatically resized. * large. It is not automatically resized.
* @return the String corresponding to the specified UTF8 string. * @return the String corresponding to the specified UTF8 string.
*/ */
private String readUTF(final int utfOffset, final int utfLength, final char[] charBuffer) { private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) {
int currentOffset = utfOffset; int currentOffset = utfOffset;
int endOffset = currentOffset + utfLength; int endOffset = currentOffset + utfLength;
int strLength = 0; int strLength = 0;

View File

@ -51,12 +51,20 @@ public final class ClassTooLargeException extends IndexOutOfBoundsException {
this.constantPoolCount = constantPoolCount; this.constantPoolCount = constantPoolCount;
} }
/** @return the internal name of the class. */ /**
* Returns the internal name of the class.
*
* @return the internal name of the class.
*/
public String getClassName() { public String getClassName() {
return className; return className;
} }
/** @return the number of constant pool items of the class. */ /**
* Returns the number of constant pool items of the class.
*
* @return the number of constant pool items of the class.
*/
public int getConstantPoolCount() { public int getConstantPoolCount() {
return constantPoolCount; return constantPoolCount;
} }

View File

@ -282,7 +282,7 @@ public class ClassWriter extends ClassVisitor {
sourceFileIndex = symbolTable.addConstantUtf8(file); sourceFileIndex = symbolTable.addConstantUtf8(file);
} }
if (debug != null) { if (debug != null) {
debugExtension = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE); debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE);
} }
} }
@ -674,7 +674,7 @@ public class ClassWriter extends ClassVisitor {
* ones. * ones.
*/ */
private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) { private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) {
Attribute[] attributes = getAttributePrototypes(); final Attribute[] attributes = getAttributePrototypes();
firstField = null; firstField = null;
lastField = null; lastField = null;
firstMethod = null; firstMethod = null;
@ -743,6 +743,7 @@ public class ClassWriter extends ClassVisitor {
* @param value the String value. * @param value the String value.
* @return the index of a new or already existing UTF8 item. * @return the index of a new or already existing UTF8 item.
*/ */
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public int newUTF8(final String value) { public int newUTF8(final String value) {
return symbolTable.addConstantUtf8(value); return symbolTable.addConstantUtf8(value);
} }
@ -947,13 +948,13 @@ public class ClassWriter extends ClassVisitor {
Class<?> class1; Class<?> class1;
try { try {
class1 = Class.forName(type1.replace('/', '.'), false, classLoader); class1 = Class.forName(type1.replace('/', '.'), false, classLoader);
} catch (Exception e) { } catch (ClassNotFoundException e) {
throw new TypeNotPresentException(type1, e); throw new TypeNotPresentException(type1, e);
} }
Class<?> class2; Class<?> class2;
try { try {
class2 = Class.forName(type2.replace('/', '.'), false, classLoader); class2 = Class.forName(type2.replace('/', '.'), false, classLoader);
} catch (Exception e) { } catch (ClassNotFoundException e) {
throw new TypeNotPresentException(type2, e); throw new TypeNotPresentException(type2, e);
} }
if (class1.isAssignableFrom(class2)) { if (class1.isAssignableFrom(class2)) {

View File

@ -36,8 +36,6 @@ package org.springframework.asm;
*/ */
final class Constants implements Opcodes { final class Constants implements Opcodes {
private Constants() {}
// The ClassFile attribute names, in the order they are defined in // The ClassFile attribute names, in the order they are defined in
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300. // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
@ -173,4 +171,6 @@ final class Constants implements Opcodes {
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA; static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA; static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_GOTO_W = 220; static final int ASM_GOTO_W = 220;
private Constants() {}
} }

View File

@ -223,6 +223,38 @@ class Frame {
*/ */
private int[] initializations; private int[] initializations;
// -----------------------------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------------------------
/**
* Constructs a new Frame.
*
* @param owner the basic block to which these input and output stack map frames correspond.
*/
Frame(final Label owner) {
this.owner = owner;
}
/**
* Sets this frame to the value of the given frame.
*
* <p>WARNING: after this method is called the two frames share the same data structures. It is
* recommended to discard the given frame to avoid unexpected side effects.
*
* @param frame The new frame value.
*/
final void copyFrom(final Frame frame) {
inputLocals = frame.inputLocals;
inputStack = frame.inputStack;
outputStackStart = 0;
outputLocals = frame.outputLocals;
outputStack = frame.outputStack;
outputStackTop = frame.outputStackTop;
initializationCount = frame.initializationCount;
initializations = frame.initializations;
}
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Static methods to get abstract types from other type formats // Static methods to get abstract types from other type formats
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -336,38 +368,6 @@ class Frame {
} }
} }
// -----------------------------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------------------------
/**
* Constructs a new Frame.
*
* @param owner the basic block to which these input and output stack map frames correspond.
*/
Frame(final Label owner) {
this.owner = owner;
}
/**
* Sets this frame to the value of the given frame.
*
* <p>WARNING: after this method is called the two frames share the same data structures. It is
* recommended to discard the given frame to avoid unexpected side effects.
*
* @param frame The new frame value.
*/
final void copyFrom(final Frame frame) {
inputLocals = frame.inputLocals;
inputStack = frame.inputStack;
outputStackStart = 0;
outputLocals = frame.outputLocals;
outputStack = frame.outputStack;
outputStackTop = frame.outputStackTop;
initializationCount = frame.initializationCount;
initializations = frame.initializations;
}
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Methods related to the input frame // Methods related to the input frame
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -415,21 +415,21 @@ class Frame {
* Sets the input frame from the given public API frame description. * Sets the input frame from the given public API frame description.
* *
* @param symbolTable the type table to use to lookup and store type {@link Symbol}. * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
* @param nLocal the number of local variables. * @param numLocal the number of local variables.
* @param local the local variable types, described using the same format as in {@link * @param local the local variable types, described using the same format as in {@link
* MethodVisitor#visitFrame}. * MethodVisitor#visitFrame}.
* @param nStack the number of operand stack elements. * @param numStack the number of operand stack elements.
* @param stack the operand stack types, described using the same format as in {@link * @param stack the operand stack types, described using the same format as in {@link
* MethodVisitor#visitFrame}. * MethodVisitor#visitFrame}.
*/ */
final void setInputFrameFromApiFormat( final void setInputFrameFromApiFormat(
final SymbolTable symbolTable, final SymbolTable symbolTable,
final int nLocal, final int numLocal,
final Object[] local, final Object[] local,
final int nStack, final int numStack,
final Object[] stack) { final Object[] stack) {
int inputLocalIndex = 0; int inputLocalIndex = 0;
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]); inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]);
if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) { if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) {
inputLocals[inputLocalIndex++] = TOP; inputLocals[inputLocalIndex++] = TOP;
@ -438,15 +438,15 @@ class Frame {
while (inputLocalIndex < inputLocals.length) { while (inputLocalIndex < inputLocals.length) {
inputLocals[inputLocalIndex++] = TOP; inputLocals[inputLocalIndex++] = TOP;
} }
int nStackTop = 0; int numStackTop = 0;
for (int i = 0; i < nStack; ++i) { for (int i = 0; i < numStack; ++i) {
if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
++nStackTop; ++numStackTop;
} }
} }
inputStack = new int[nStack + nStackTop]; inputStack = new int[numStack + numStackTop];
int inputStackIndex = 0; int inputStackIndex = 0;
for (int i = 0; i < nStack; ++i) { for (int i = 0; i < numStack; ++i) {
inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]); inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]);
if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
inputStack[inputStackIndex++] = TOP; inputStack[inputStackIndex++] = TOP;
@ -1122,13 +1122,13 @@ class Frame {
// Compute the concrete types of the local variables at the end of the basic block corresponding // Compute the concrete types of the local variables at the end of the basic block corresponding
// to this frame, by resolving its abstract output types, and merge these concrete types with // to this frame, by resolving its abstract output types, and merge these concrete types with
// those of the local variables in the input frame of dstFrame. // those of the local variables in the input frame of dstFrame.
int nLocal = inputLocals.length; int numLocal = inputLocals.length;
int nStack = inputStack.length; int numStack = inputStack.length;
if (dstFrame.inputLocals == null) { if (dstFrame.inputLocals == null) {
dstFrame.inputLocals = new int[nLocal]; dstFrame.inputLocals = new int[numLocal];
frameChanged = true; frameChanged = true;
} }
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
int concreteOutputType; int concreteOutputType;
if (outputLocals != null && i < outputLocals.length) { if (outputLocals != null && i < outputLocals.length) {
int abstractOutputType = outputLocals[i]; int abstractOutputType = outputLocals[i];
@ -1152,7 +1152,7 @@ class Frame {
// By definition, a STACK_KIND type designates the concrete type of a local variable at // By definition, a STACK_KIND type designates the concrete type of a local variable at
// the beginning of the basic block corresponding to this frame (which is known when // the beginning of the basic block corresponding to this frame (which is known when
// this method is called, but was not when the abstract type was computed). // this method is called, but was not when the abstract type was computed).
concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP; concreteOutputType = TOP;
@ -1181,7 +1181,7 @@ class Frame {
// frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one
// element stack containing the caught exception type). // element stack containing the caught exception type).
if (catchTypeIndex > 0) { if (catchTypeIndex > 0) {
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i); frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i);
} }
if (dstFrame.inputStack == null) { if (dstFrame.inputStack == null) {
@ -1195,15 +1195,15 @@ class Frame {
// Compute the concrete types of the stack operands at the end of the basic block corresponding // Compute the concrete types of the stack operands at the end of the basic block corresponding
// to this frame, by resolving its abstract output types, and merge these concrete types with // to this frame, by resolving its abstract output types, and merge these concrete types with
// those of the stack operands in the input frame of dstFrame. // those of the stack operands in the input frame of dstFrame.
int nInputStack = inputStack.length + outputStackStart; int numInputStack = inputStack.length + outputStackStart;
if (dstFrame.inputStack == null) { if (dstFrame.inputStack == null) {
dstFrame.inputStack = new int[nInputStack + outputStackTop]; dstFrame.inputStack = new int[numInputStack + outputStackTop];
frameChanged = true; frameChanged = true;
} }
// First, do this for the stack operands that have not been popped in the basic block // First, do this for the stack operands that have not been popped in the basic block
// corresponding to this frame, and which are therefore equal to their value in the input // corresponding to this frame, and which are therefore equal to their value in the input
// frame (except for uninitialized types, which may have been initialized). // frame (except for uninitialized types, which may have been initialized).
for (int i = 0; i < nInputStack; ++i) { for (int i = 0; i < numInputStack; ++i) {
int concreteOutputType = inputStack[i]; int concreteOutputType = inputStack[i];
if (initializations != null) { if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType); concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
@ -1224,7 +1224,7 @@ class Frame {
concreteOutputType = TOP; concreteOutputType = TOP;
} }
} else if (kind == STACK_KIND) { } else if (kind == STACK_KIND) {
concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP; concreteOutputType = TOP;
@ -1235,7 +1235,8 @@ class Frame {
if (initializations != null) { if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType); concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
} }
frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, nInputStack + i); frameChanged |=
merge(symbolTable, concreteOutputType, dstFrame.inputStack, numInputStack + i);
} }
return frameChanged; return frameChanged;
} }
@ -1348,38 +1349,38 @@ class Frame {
// Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and
// all trailing TOP types. // all trailing TOP types.
int[] localTypes = inputLocals; int[] localTypes = inputLocals;
int nLocal = 0; int numLocal = 0;
int nTrailingTop = 0; int numTrailingTop = 0;
int i = 0; int i = 0;
while (i < localTypes.length) { while (i < localTypes.length) {
int localType = localTypes[i]; int localType = localTypes[i];
i += (localType == LONG || localType == DOUBLE) ? 2 : 1; i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
if (localType == TOP) { if (localType == TOP) {
nTrailingTop++; numTrailingTop++;
} else { } else {
nLocal += nTrailingTop + 1; numLocal += numTrailingTop + 1;
nTrailingTop = 0; numTrailingTop = 0;
} }
} }
// Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE. // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE.
int[] stackTypes = inputStack; int[] stackTypes = inputStack;
int nStack = 0; int numStack = 0;
i = 0; i = 0;
while (i < stackTypes.length) { while (i < stackTypes.length) {
int stackType = stackTypes[i]; int stackType = stackTypes[i];
i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
nStack++; numStack++;
} }
// Visit the frame and its content. // Visit the frame and its content.
int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, nLocal, nStack); int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, numLocal, numStack);
i = 0; i = 0;
while (nLocal-- > 0) { while (numLocal-- > 0) {
int localType = localTypes[i]; int localType = localTypes[i];
i += (localType == LONG || localType == DOUBLE) ? 2 : 1; i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
methodWriter.visitAbstractType(frameIndex++, localType); methodWriter.visitAbstractType(frameIndex++, localType);
} }
i = 0; i = 0;
while (nStack-- > 0) { while (numStack-- > 0) {
int stackType = stackTypes[i]; int stackType = stackTypes[i];
i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
methodWriter.visitAbstractType(frameIndex++, stackType); methodWriter.visitAbstractType(frameIndex++, stackType);

View File

@ -178,7 +178,7 @@ public class Label {
* and {@link #FORWARD_REFERENCE_HANDLE_MASK}. * and {@link #FORWARD_REFERENCE_HANDLE_MASK}.
* </ul> * </ul>
* *
* For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is * <p>For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is
* equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1 * equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1
* (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after * (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after
* the start of the instruction itself). For the default case of a lookupswitch instruction at * the start of the instruction itself). For the default case of a lookupswitch instruction at

View File

@ -61,22 +61,38 @@ public final class MethodTooLargeException extends IndexOutOfBoundsException {
this.codeSize = codeSize; this.codeSize = codeSize;
} }
/** @return the internal name of the owner class. */ /**
* Returns the internal name of the owner class.
*
* @return the internal name of the owner class.
*/
public String getClassName() { public String getClassName() {
return className; return className;
} }
/** @return the name of the method. */ /**
* Returns the name of the method.
*
* @return the name of the method.
*/
public String getMethodName() { public String getMethodName() {
return methodName; return methodName;
} }
/** @return the descriptor of the method. */ /**
* Returns the descriptor of the method.
*
* @return the descriptor of the method.
*/
public String getDescriptor() { public String getDescriptor() {
return descriptor; return descriptor;
} }
/** @return the size of the method's Code attribute, in bytes. */ /**
* Returns the size of the method's Code attribute, in bytes.
*
* @return the size of the method's Code attribute, in bytes.
*/
public int getCodeSize() { public int getCodeSize() {
return codeSize; return codeSize;
} }

View File

@ -243,15 +243,15 @@ public abstract class MethodVisitor {
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same locals as the * <li>{@link Opcodes#F_SAME} representing frame with exactly the same locals as the
* previous frame and with the empty stack. * previous frame and with the empty stack.
* <li>{@link Opcodes#F_SAME1} representing frame with exactly the same locals as the * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same locals as the
* previous frame and with single value on the stack ( <code>nStack</code> is 1 and * previous frame and with single value on the stack ( <code>numStack</code> is 1 and
* <code>stack[0]</code> contains value for the type of the stack item). * <code>stack[0]</code> contains value for the type of the stack item).
* <li>{@link Opcodes#F_APPEND} representing frame with current locals are the same as the * <li>{@link Opcodes#F_APPEND} representing frame with current locals are the same as the
* locals in the previous frame, except that additional locals are defined (<code> * locals in the previous frame, except that additional locals are defined (<code>
* nLocal</code> is 1, 2 or 3 and <code>local</code> elements contains values * numLocal</code> is 1, 2 or 3 and <code>local</code> elements contains values
* representing added types). * representing added types).
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the same as the * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the same as the
* locals in the previous frame, except that the last 1-3 locals are absent and with * locals in the previous frame, except that the last 1-3 locals are absent and with
* the empty stack (<code>nLocals</code> is 1, 2 or 3). * the empty stack (<code>numLocal</code> is 1, 2 or 3).
* <li>{@link Opcodes#F_FULL} representing complete frame data. * <li>{@link Opcodes#F_FULL} representing complete frame data.
* </ul> * </ul>
* </ul> * </ul>
@ -264,7 +264,7 @@ public abstract class MethodVisitor {
* @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
* Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
* @param nLocal the number of local variables in the visited frame. * @param numLocal the number of local variables in the visited frame.
* @param local the local variable types in this frame. This array must not be modified. Primitive * @param local the local variable types in this frame. This array must not be modified. Primitive
* types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
* Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
@ -272,7 +272,7 @@ public abstract class MethodVisitor {
* Reference types are represented by String objects (representing internal names), and * Reference types are represented by String objects (representing internal names), and
* uninitialized types by Label objects (this label designates the NEW instruction that * uninitialized types by Label objects (this label designates the NEW instruction that
* created this uninitialized value). * created this uninitialized value).
* @param nStack the number of operand stack elements in the visited frame. * @param numStack the number of operand stack elements in the visited frame.
* @param stack the operand stack types in this frame. This array must not be modified. Its * @param stack the operand stack types in this frame. This array must not be modified. Its
* content has the same format as the "local" array. * content has the same format as the "local" array.
* @throws IllegalStateException if a frame is visited just after another one, without any * @throws IllegalStateException if a frame is visited just after another one, without any
@ -281,12 +281,12 @@ public abstract class MethodVisitor {
*/ */
public void visitFrame( public void visitFrame(
final int type, final int type,
final int nLocal, final int numLocal,
final Object[] local, final Object[] local,
final int nStack, final int numStack,
final Object[] stack) { final Object[] stack) {
if (mv != null) { if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack); mv.visitFrame(type, numLocal, local, numStack, stack);
} }
} }
@ -390,7 +390,7 @@ public abstract class MethodVisitor {
* Type#getInternalName()}). * Type#getInternalName()}).
* @param name the method's name. * @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}). * @param descriptor the method's descriptor (see {@link Type}).
* @deprecated * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/ */
@Deprecated @Deprecated
public void visitMethodInsn( public void visitMethodInsn(

View File

@ -531,11 +531,10 @@ final class MethodWriter extends MethodVisitor {
* The current stack map frame. The first element contains the bytecode offset of the instruction * The current stack map frame. The first element contains the bytecode offset of the instruction
* to which the frame corresponds, the second element is the number of locals and the third one is * to which the frame corresponds, the second element is the number of locals and the third one is
* the number of stack elements. The local variables start at index 3 and are followed by the * the number of stack elements. The local variables start at index 3 and are followed by the
* operand stack elements. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack, * operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack.
* frame[3] = nLocal. Local variables and operand stack entries contain abstract types, as defined * Local variables and operand stack entries contain abstract types, as defined in {@link Frame},
* in {@link Frame}, but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} * but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} or {@link
* or {@link Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array * Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array entry.
* entry.
*/ */
private int[] currentFrame; private int[] currentFrame;
@ -745,9 +744,9 @@ final class MethodWriter extends MethodVisitor {
@Override @Override
public void visitFrame( public void visitFrame(
final int type, final int type,
final int nLocal, final int numLocal,
final Object[] local, final Object[] local,
final int nStack, final int numStack,
final Object[] stack) { final Object[] stack) {
if (compute == COMPUTE_ALL_FRAMES) { if (compute == COMPUTE_ALL_FRAMES) {
return; return;
@ -760,12 +759,12 @@ final class MethodWriter extends MethodVisitor {
// can't be set if EXPAND_ASM_INSNS is not used). // can't be set if EXPAND_ASM_INSNS is not used).
currentBasicBlock.frame = new CurrentFrame(currentBasicBlock); currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
currentBasicBlock.frame.setInputFrameFromDescriptor( currentBasicBlock.frame.setInputFrameFromDescriptor(
symbolTable, accessFlags, descriptor, nLocal); symbolTable, accessFlags, descriptor, numLocal);
currentBasicBlock.frame.accept(this); currentBasicBlock.frame.accept(this);
} else { } else {
if (type == Opcodes.F_NEW) { if (type == Opcodes.F_NEW) {
currentBasicBlock.frame.setInputFrameFromApiFormat( currentBasicBlock.frame.setInputFrameFromApiFormat(
symbolTable, nLocal, local, nStack, stack); symbolTable, numLocal, local, numStack, stack);
} else { } else {
// In this case type is equal to F_INSERT by hypothesis, and currentBlock.frame contains // In this case type is equal to F_INSERT by hypothesis, and currentBlock.frame contains
// the stack map frame at the current instruction, computed from the last F_NEW frame // the stack map frame at the current instruction, computed from the last F_NEW frame
@ -781,12 +780,12 @@ final class MethodWriter extends MethodVisitor {
symbolTable, accessFlags, descriptor, argumentsSize); symbolTable, accessFlags, descriptor, argumentsSize);
implicitFirstFrame.accept(this); implicitFirstFrame.accept(this);
} }
currentLocals = nLocal; currentLocals = numLocal;
int frameIndex = visitFrameStart(code.length, nLocal, nStack); int frameIndex = visitFrameStart(code.length, numLocal, numStack);
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
} }
for (int i = 0; i < nStack; ++i) { for (int i = 0; i < numStack; ++i) {
currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]); currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
} }
visitFrameEnd(); visitFrameEnd();
@ -808,26 +807,26 @@ final class MethodWriter extends MethodVisitor {
switch (type) { switch (type) {
case Opcodes.F_FULL: case Opcodes.F_FULL:
currentLocals = nLocal; currentLocals = numLocal;
stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
putFrameType(local[i]); putFrameType(local[i]);
} }
stackMapTableEntries.putShort(nStack); stackMapTableEntries.putShort(numStack);
for (int i = 0; i < nStack; ++i) { for (int i = 0; i < numStack; ++i) {
putFrameType(stack[i]); putFrameType(stack[i]);
} }
break; break;
case Opcodes.F_APPEND: case Opcodes.F_APPEND:
currentLocals += nLocal; currentLocals += numLocal;
stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocal).putShort(offsetDelta); stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta);
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < numLocal; ++i) {
putFrameType(local[i]); putFrameType(local[i]);
} }
break; break;
case Opcodes.F_CHOP: case Opcodes.F_CHOP:
currentLocals -= nLocal; currentLocals -= numLocal;
stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - nLocal).putShort(offsetDelta); stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta);
break; break;
case Opcodes.F_SAME: case Opcodes.F_SAME:
if (offsetDelta < 64) { if (offsetDelta < 64) {
@ -855,8 +854,8 @@ final class MethodWriter extends MethodVisitor {
} }
if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
relativeStackSize = nStack; relativeStackSize = numStack;
for (int i = 0; i < nStack; ++i) { for (int i = 0; i < numStack; ++i) {
if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
relativeStackSize++; relativeStackSize++;
} }
@ -866,7 +865,7 @@ final class MethodWriter extends MethodVisitor {
} }
} }
maxStack = Math.max(maxStack, nStack); maxStack = Math.max(maxStack, numStack);
maxLocals = Math.max(maxLocals, currentLocals); maxLocals = Math.max(maxLocals, currentLocals);
} }
@ -1649,7 +1648,7 @@ final class MethodWriter extends MethodVisitor {
code.data[endOffset] = (byte) Opcodes.ATHROW; code.data[endOffset] = (byte) Opcodes.ATHROW;
// Emit a frame for this unreachable block, with no local and a Throwable on the stack // Emit a frame for this unreachable block, with no local and a Throwable on the stack
// (so that the ATHROW could consume this Throwable if it were reachable). // (so that the ATHROW could consume this Throwable if it were reachable).
int frameIndex = visitFrameStart(startOffset, /* nLocal = */ 0, /* nStack = */ 1); int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
currentFrame[frameIndex] = currentFrame[frameIndex] =
Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
visitFrameEnd(); visitFrameEnd();
@ -1821,18 +1820,18 @@ final class MethodWriter extends MethodVisitor {
* Starts the visit of a new stack map frame, stored in {@link #currentFrame}. * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
* *
* @param offset the bytecode offset of the instruction to which the frame corresponds. * @param offset the bytecode offset of the instruction to which the frame corresponds.
* @param nLocal the number of local variables in the frame. * @param numLocal the number of local variables in the frame.
* @param nStack the number of stack elements in the frame. * @param numStack the number of stack elements in the frame.
* @return the index of the next element to be written in this frame. * @return the index of the next element to be written in this frame.
*/ */
int visitFrameStart(final int offset, final int nLocal, final int nStack) { int visitFrameStart(final int offset, final int numLocal, final int numStack) {
int frameLength = 3 + nLocal + nStack; int frameLength = 3 + numLocal + numStack;
if (currentFrame == null || currentFrame.length < frameLength) { if (currentFrame == null || currentFrame.length < frameLength) {
currentFrame = new int[frameLength]; currentFrame = new int[frameLength];
} }
currentFrame[0] = offset; currentFrame[0] = offset;
currentFrame[1] = nLocal; currentFrame[1] = numLocal;
currentFrame[2] = nStack; currentFrame[2] = numStack;
return 3; return 3;
} }
@ -1865,25 +1864,25 @@ final class MethodWriter extends MethodVisitor {
/** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */ /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
private void putFrame() { private void putFrame() {
final int nLocal = currentFrame[1]; final int numLocal = currentFrame[1];
final int nStack = currentFrame[2]; final int numStack = currentFrame[2];
if (symbolTable.getMajorVersion() < Opcodes.V1_6) { if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
// Generate a StackMap attribute entry, which are always uncompressed. // Generate a StackMap attribute entry, which are always uncompressed.
stackMapTableEntries.putShort(currentFrame[0]).putShort(nLocal); stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal);
putAbstractTypes(3, 3 + nLocal); putAbstractTypes(3, 3 + numLocal);
stackMapTableEntries.putShort(nStack); stackMapTableEntries.putShort(numStack);
putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
return; return;
} }
final int offsetDelta = final int offsetDelta =
stackMapTableNumberOfEntries == 0 stackMapTableNumberOfEntries == 0
? currentFrame[0] ? currentFrame[0]
: currentFrame[0] - previousFrame[0] - 1; : currentFrame[0] - previousFrame[0] - 1;
final int previousNlocal = previousFrame[1]; final int previousNumlocal = previousFrame[1];
final int nLocalDelta = nLocal - previousNlocal; final int numLocalDelta = numLocal - previousNumlocal;
int type = Frame.FULL_FRAME; int type = Frame.FULL_FRAME;
if (nStack == 0) { if (numStack == 0) {
switch (nLocalDelta) { switch (numLocalDelta) {
case -3: case -3:
case -2: case -2:
case -1: case -1:
@ -1901,7 +1900,7 @@ final class MethodWriter extends MethodVisitor {
// Keep the FULL_FRAME type. // Keep the FULL_FRAME type.
break; break;
} }
} else if (nLocalDelta == 0 && nStack == 1) { } else if (numLocalDelta == 0 && numStack == 1) {
type = type =
offsetDelta < 63 offsetDelta < 63
? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
@ -1910,7 +1909,7 @@ final class MethodWriter extends MethodVisitor {
if (type != Frame.FULL_FRAME) { if (type != Frame.FULL_FRAME) {
// Verify if locals are the same as in the previous frame. // Verify if locals are the same as in the previous frame.
int frameIndex = 3; int frameIndex = 3;
for (int i = 0; i < previousNlocal && i < nLocal; i++) { for (int i = 0; i < previousNumlocal && i < numLocal; i++) {
if (currentFrame[frameIndex] != previousFrame[frameIndex]) { if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
type = Frame.FULL_FRAME; type = Frame.FULL_FRAME;
break; break;
@ -1924,30 +1923,34 @@ final class MethodWriter extends MethodVisitor {
break; break;
case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME: case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
putAbstractTypes(3 + nLocal, 4 + nLocal); putAbstractTypes(3 + numLocal, 4 + numLocal);
break; break;
case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
stackMapTableEntries stackMapTableEntries
.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
.putShort(offsetDelta); .putShort(offsetDelta);
putAbstractTypes(3 + nLocal, 4 + nLocal); putAbstractTypes(3 + numLocal, 4 + numLocal);
break; break;
case Frame.SAME_FRAME_EXTENDED: case Frame.SAME_FRAME_EXTENDED:
stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
break; break;
case Frame.CHOP_FRAME: case Frame.CHOP_FRAME:
stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); stackMapTableEntries
.putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
.putShort(offsetDelta);
break; break;
case Frame.APPEND_FRAME: case Frame.APPEND_FRAME:
stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); stackMapTableEntries
putAbstractTypes(3 + previousNlocal, 3 + nLocal); .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
.putShort(offsetDelta);
putAbstractTypes(3 + previousNumlocal, 3 + numLocal);
break; break;
case Frame.FULL_FRAME: case Frame.FULL_FRAME:
default: default:
stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
putAbstractTypes(3, 3 + nLocal); putAbstractTypes(3, 3 + numLocal);
stackMapTableEntries.putShort(nStack); stackMapTableEntries.putShort(numStack);
putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
} }
} }

View File

@ -38,6 +38,7 @@ package org.springframework.asm;
* @author Eric Bruneton * @author Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
// DontCheck(InterfaceIsType): can't be fixed (for backward binary compatibility).
public interface Opcodes { public interface Opcodes {
// ASM API versions. // ASM API versions.

View File

@ -227,6 +227,8 @@ abstract class Symbol {
} }
/** /**
* Returns the result {@link Type#getArgumentsAndReturnSizes} on {@link #value}.
*
* @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in
* {@link #info} for efficiency). This should only be used for {@link * {@link #info} for efficiency). This should only be used for {@link
* #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link

View File

@ -39,58 +39,6 @@ package org.springframework.asm;
*/ */
final class SymbolTable { final class SymbolTable {
/**
* An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
* which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
* duplicate symbols). See {@link #entries}.
*
* @author Eric Bruneton
*/
private static class Entry extends Symbol {
/** The hash code of this entry. */
final int hashCode;
/**
* Another entry (and so on recursively) having the same hash code (modulo the size of {@link
* #entries}) as this one.
*/
Entry next;
Entry(
final int index,
final int tag,
final String owner,
final String name,
final String value,
final long data,
final int hashCode) {
super(index, tag, owner, name, value, data);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, data);
this.hashCode = hashCode;
}
Entry(
final int index, final int tag, final String name, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
this.hashCode = hashCode;
}
}
/** /**
* The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link
* ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link
@ -224,7 +172,7 @@ final class SymbolTable {
break; break;
case Symbol.CONSTANT_INTEGER_TAG: case Symbol.CONSTANT_INTEGER_TAG:
case Symbol.CONSTANT_FLOAT_TAG: case Symbol.CONSTANT_FLOAT_TAG:
addConstantInteger(itemIndex, itemTag, classReader.readInt(itemOffset)); addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset));
break; break;
case Symbol.CONSTANT_NAME_AND_TYPE_TAG: case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
addConstantNameAndType( addConstantNameAndType(
@ -234,10 +182,10 @@ final class SymbolTable {
break; break;
case Symbol.CONSTANT_LONG_TAG: case Symbol.CONSTANT_LONG_TAG:
case Symbol.CONSTANT_DOUBLE_TAG: case Symbol.CONSTANT_DOUBLE_TAG:
addConstantLong(itemIndex, itemTag, classReader.readLong(itemOffset)); addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset));
break; break;
case Symbol.CONSTANT_UTF8_TAG: case Symbol.CONSTANT_UTF8_TAG:
addConstantUtf8(itemIndex, classReader.readUTF(itemIndex, charBuffer)); addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer));
break; break;
case Symbol.CONSTANT_METHOD_HANDLE_TAG: case Symbol.CONSTANT_METHOD_HANDLE_TAG:
int memberRefItemOffset = int memberRefItemOffset =
@ -331,6 +279,8 @@ final class SymbolTable {
} }
/** /**
* Returns the ClassReader from which this SymbolTable was constructed.
*
* @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it * @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it
* was constructed from scratch. * was constructed from scratch.
*/ */
@ -338,12 +288,20 @@ final class SymbolTable {
return sourceClassReader; return sourceClassReader;
} }
/** @return the major version of the class to which this symbol table belongs. */ /**
* Returns the major version of the class to which this symbol table belongs.
*
* @return the major version of the class to which this symbol table belongs.
*/
int getMajorVersion() { int getMajorVersion() {
return majorVersion; return majorVersion;
} }
/** @return the internal name of the class to which this symbol table belongs. */ /**
* Returns the internal name of the class to which this symbol table belongs.
*
* @return the internal name of the class to which this symbol table belongs.
*/
String getClassName() { String getClassName() {
return className; return className;
} }
@ -362,12 +320,20 @@ final class SymbolTable {
return addConstantClass(className).index; return addConstantClass(className).index;
} }
/** @return the number of items in this symbol table's constant_pool array (plus 1). */ /**
* Returns the number of items in this symbol table's constant_pool array (plus 1).
*
* @return the number of items in this symbol table's constant_pool array (plus 1).
*/
int getConstantPoolCount() { int getConstantPoolCount() {
return constantPoolCount; return constantPoolCount;
} }
/** @return the length in bytes of this symbol table's constant_pool array. */ /**
* Returns the length in bytes of this symbol table's constant_pool array.
*
* @return the length in bytes of this symbol table's constant_pool array.
*/
int getConstantPoolLength() { int getConstantPoolLength() {
return constantPool.length; return constantPool.length;
} }
@ -418,6 +384,8 @@ final class SymbolTable {
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
/** /**
* Returns the list of entries which can potentially have the given hash code.
*
* @param hashCode a {@link Entry#hashCode} value. * @param hashCode a {@link Entry#hashCode} value.
* @return the list of entries which can potentially have the given hash code. The list is stored * @return the list of entries which can potentially have the given hash code. The list is stored
* via the {@link Entry#next} field. * via the {@link Entry#next} field.
@ -644,7 +612,7 @@ final class SymbolTable {
* @return a new or already existing Symbol with the given value. * @return a new or already existing Symbol with the given value.
*/ */
Symbol addConstantInteger(final int value) { Symbol addConstantInteger(final int value) {
return addConstantInteger(Symbol.CONSTANT_INTEGER_TAG, value); return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value);
} }
/** /**
@ -655,7 +623,7 @@ final class SymbolTable {
* @return a new or already existing Symbol with the given value. * @return a new or already existing Symbol with the given value.
*/ */
Symbol addConstantFloat(final float value) { Symbol addConstantFloat(final float value) {
return addConstantInteger(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value)); return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
} }
/** /**
@ -666,7 +634,7 @@ final class SymbolTable {
* @param value an int or float. * @param value an int or float.
* @return a constant pool constant with the given tag and primitive values. * @return a constant pool constant with the given tag and primitive values.
*/ */
private Symbol addConstantInteger(final int tag, final int value) { private Symbol addConstantIntegerOrFloat(final int tag, final int value) {
int hashCode = hash(tag, value); int hashCode = hash(tag, value);
Entry entry = get(hashCode); Entry entry = get(hashCode);
while (entry != null) { while (entry != null) {
@ -687,7 +655,7 @@ final class SymbolTable {
* @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
* @param value an int or float. * @param value an int or float.
*/ */
private void addConstantInteger(final int index, final int tag, final int value) { private void addConstantIntegerOrFloat(final int index, final int tag, final int value) {
add(new Entry(index, tag, value, hash(tag, value))); add(new Entry(index, tag, value, hash(tag, value)));
} }
@ -699,7 +667,7 @@ final class SymbolTable {
* @return a new or already existing Symbol with the given value. * @return a new or already existing Symbol with the given value.
*/ */
Symbol addConstantLong(final long value) { Symbol addConstantLong(final long value) {
return addConstantLong(Symbol.CONSTANT_LONG_TAG, value); return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value);
} }
/** /**
@ -710,7 +678,7 @@ final class SymbolTable {
* @return a new or already existing Symbol with the given value. * @return a new or already existing Symbol with the given value.
*/ */
Symbol addConstantDouble(final double value) { Symbol addConstantDouble(final double value) {
return addConstantLong(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value)); return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
} }
/** /**
@ -721,7 +689,7 @@ final class SymbolTable {
* @param value a long or double. * @param value a long or double.
* @return a constant pool constant with the given tag and primitive values. * @return a constant pool constant with the given tag and primitive values.
*/ */
private Symbol addConstantLong(final int tag, final long value) { private Symbol addConstantLongOrDouble(final int tag, final long value) {
int hashCode = hash(tag, value); int hashCode = hash(tag, value);
Entry entry = get(hashCode); Entry entry = get(hashCode);
while (entry != null) { while (entry != null) {
@ -737,13 +705,14 @@ final class SymbolTable {
} }
/** /**
* Adds a new CONSTANT_Double_info to the constant pool of this symbol table. * Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
* table.
* *
* @param index the constant pool index of the new Symbol. * @param index the constant pool index of the new Symbol.
* @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
* @param value a long or double. * @param value a long or double.
*/ */
private void addConstantLong(final int index, final int tag, final long value) { private void addConstantLongOrDouble(final int index, final int tag, final long value) {
add(new Entry(index, tag, value, hash(tag, value))); add(new Entry(index, tag, value, hash(tag, value)));
} }
@ -1149,6 +1118,8 @@ final class SymbolTable {
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
/** /**
* Returns the type table element whose index is given.
*
* @param typeIndex a type table index. * @param typeIndex a type table index.
* @return the type table element whose index is given. * @return the type table element whose index is given.
*/ */
@ -1172,7 +1143,7 @@ final class SymbolTable {
} }
entry = entry.next; entry = entry.next;
} }
return addType(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode)); return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
} }
/** /**
@ -1196,7 +1167,7 @@ final class SymbolTable {
} }
entry = entry.next; entry = entry.next;
} }
return addType( return addTypeInternal(
new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode)); new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
} }
@ -1237,7 +1208,7 @@ final class SymbolTable {
* @return the index in {@link #typeTable} where the given type was added, which is also equal to * @return the index in {@link #typeTable} where the given type was added, which is also equal to
* entry's index by hypothesis. * entry's index by hypothesis.
*/ */
private int addType(final Entry entry) { private int addTypeInternal(final Entry entry) {
if (typeTable == null) { if (typeTable == null) {
typeTable = new Entry[16]; typeTable = new Entry[16];
} }
@ -1292,4 +1263,56 @@ final class SymbolTable {
final int value4) { final int value4) {
return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4); return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
} }
/**
* An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
* which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
* duplicate symbols). See {@link #entries}.
*
* @author Eric Bruneton
*/
private static class Entry extends Symbol {
/** The hash code of this entry. */
final int hashCode;
/**
* Another entry (and so on recursively) having the same hash code (modulo the size of {@link
* #entries}) as this one.
*/
Entry next;
Entry(
final int index,
final int tag,
final String owner,
final String name,
final String value,
final long data,
final int hashCode) {
super(index, tag, owner, name, value, data);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, data);
this.hashCode = hashCode;
}
Entry(
final int index, final int tag, final String name, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
this.hashCode = hashCode;
}
}
} }

View File

@ -146,10 +146,6 @@ public class Type {
*/ */
private final int valueEnd; private final int valueEnd;
// -----------------------------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------------------------
/** /**
* Constructs a reference type. * Constructs a reference type.
* *
@ -167,6 +163,10 @@ public class Type {
this.valueEnd = valueEnd; this.valueEnd = valueEnd;
} }
// -----------------------------------------------------------------------------------------------
// Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc.
// -----------------------------------------------------------------------------------------------
/** /**
* Returns the {@link Type} corresponding to the given type descriptor. * Returns the {@link Type} corresponding to the given type descriptor.
* *
@ -174,40 +174,7 @@ public class Type {
* @return the {@link Type} corresponding to the given type descriptor. * @return the {@link Type} corresponding to the given type descriptor.
*/ */
public static Type getType(final String typeDescriptor) { public static Type getType(final String typeDescriptor) {
return getType(typeDescriptor, 0, typeDescriptor.length()); return getTypeInternal(typeDescriptor, 0, typeDescriptor.length());
}
/**
* Returns the {@link Type} corresponding to the given internal name.
*
* @param internalName an internal name.
* @return the {@link Type} corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
return new Type(
internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
}
/**
* Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
* Type.getType(methodDescriptor)</code>.
*
* @param methodDescriptor a method descriptor.
* @return the {@link Type} corresponding to the given method descriptor.
*/
public static Type getMethodType(final String methodDescriptor) {
return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
}
/**
* Returns the method {@link Type} corresponding to the given argument and return types.
*
* @param returnType the return type of the method.
* @param argumentTypes the argument types of the method.
* @return the method {@link Type} corresponding to the given argument and return types.
*/
public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
return getType(getMethodDescriptor(returnType, argumentTypes));
} }
/** /**
@ -264,6 +231,60 @@ public class Type {
return getType(getMethodDescriptor(method)); return getType(getMethodDescriptor(method));
} }
/**
* Returns the type of the elements of this array type. This method should only be used for an
* array type.
*
* @return Returns the type of the elements of this array type.
*/
public Type getElementType() {
final int numDimensions = getDimensions();
return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd);
}
/**
* Returns the {@link Type} corresponding to the given internal name.
*
* @param internalName an internal name.
* @return the {@link Type} corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
return new Type(
internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
}
/**
* Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
* Type.getType(methodDescriptor)</code>.
*
* @param methodDescriptor a method descriptor.
* @return the {@link Type} corresponding to the given method descriptor.
*/
public static Type getMethodType(final String methodDescriptor) {
return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
}
/**
* Returns the method {@link Type} corresponding to the given argument and return types.
*
* @param returnType the return type of the method.
* @param argumentTypes the argument types of the method.
* @return the method {@link Type} corresponding to the given argument and return types.
*/
public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
return getType(getMethodDescriptor(returnType, argumentTypes));
}
/**
* Returns the argument types of methods of this type. This method should only be used for method
* types.
*
* @return the argument types of methods of this type.
*/
public Type[] getArgumentTypes() {
return getArgumentTypes(getDescriptor());
}
/** /**
* Returns the {@link Type} values corresponding to the argument types of the given method * Returns the {@link Type} values corresponding to the argument types of the given method
* descriptor. * descriptor.
@ -307,7 +328,7 @@ public class Type {
} }
} }
argumentTypes[currentArgumentTypeIndex++] = argumentTypes[currentArgumentTypeIndex++] =
getType(methodDescriptor, currentArgumentTypeOffset, currentOffset); getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
} }
return argumentTypes; return argumentTypes;
} }
@ -327,6 +348,16 @@ public class Type {
return types; return types;
} }
/**
* Returns the return type of methods of this type. This method should only be used for method
* types.
*
* @return the return type of methods of this type.
*/
public Type getReturnType() {
return getReturnType(getDescriptor());
}
/** /**
* Returns the {@link Type} corresponding to the return type of the given method descriptor. * Returns the {@link Type} corresponding to the return type of the given method descriptor.
* *
@ -347,7 +378,7 @@ public class Type {
} }
} }
} }
return getType(methodDescriptor, currentOffset + 1, methodDescriptor.length()); return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length());
} }
/** /**
@ -360,47 +391,6 @@ public class Type {
return getType(method.getReturnType()); return getType(method.getReturnType());
} }
/**
* Computes the size of the arguments and of the return value of a method.
*
* @param methodDescriptor a method descriptor.
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
int argumentsSize = 1;
// Skip the first character, which is always a '('.
int currentOffset = 1;
int currentChar = methodDescriptor.charAt(currentOffset);
// Parse the argument types and compute their size, one at a each loop iteration.
while (currentChar != ')') {
if (currentChar == 'J' || currentChar == 'D') {
currentOffset++;
argumentsSize += 2;
} else {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
while (methodDescriptor.charAt(currentOffset++) != ';') {
// Skip the argument descriptor content.
}
}
argumentsSize += 1;
}
currentChar = methodDescriptor.charAt(currentOffset);
}
currentChar = methodDescriptor.charAt(currentOffset + 1);
if (currentChar == 'V') {
return argumentsSize << 2;
} else {
int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1;
return argumentsSize << 2 | returnSize;
}
}
/** /**
* Returns the {@link Type} corresponding to the given field or method descriptor. * Returns the {@link Type} corresponding to the given field or method descriptor.
* *
@ -411,7 +401,7 @@ public class Type {
* descriptorBuffer. * descriptorBuffer.
* @return the {@link Type} corresponding to the given type descriptor. * @return the {@link Type} corresponding to the given type descriptor.
*/ */
private static Type getType( private static Type getTypeInternal(
final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) { final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
switch (descriptorBuffer.charAt(descriptorBegin)) { switch (descriptorBuffer.charAt(descriptorBegin)) {
case 'V': case 'V':
@ -444,45 +434,9 @@ public class Type {
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Accessors // Methods to get class names, internal names or descriptors.
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
/**
* Returns the sort of this type.
*
* @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
* #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
* {@link #METHOD}.
*/
public int getSort() {
return sort == INTERNAL ? OBJECT : sort;
}
/**
* Returns the number of dimensions of this array type. This method should only be used for an
* array type.
*
* @return the number of dimensions of this array type.
*/
public int getDimensions() {
int numDimensions = 1;
while (valueBuffer.charAt(valueBegin + numDimensions) == '[') {
numDimensions++;
}
return numDimensions;
}
/**
* Returns the type of the elements of this array type. This method should only be used for an
* array type.
*
* @return Returns the type of the elements of this array type.
*/
public Type getElementType() {
final int numDimensions = getDimensions();
return getType(valueBuffer, valueBegin + numDimensions, valueEnd);
}
/** /**
* Returns the binary name of the class corresponding to this type. This method must not be used * Returns the binary name of the class corresponding to this type. This method must not be used
* on method types. * on method types.
@ -535,42 +489,16 @@ public class Type {
} }
/** /**
* Returns the argument types of methods of this type. This method should only be used for method * Returns the internal name of the given class. The internal name of a class is its fully
* types. * qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
* *
* @return the argument types of methods of this type. * @param clazz an object or array class.
* @return the internal name of the given class.
*/ */
public Type[] getArgumentTypes() { public static String getInternalName(final Class<?> clazz) {
return getArgumentTypes(getDescriptor()); return clazz.getName().replace('.', '/');
} }
/**
* Returns the return type of methods of this type. This method should only be used for method
* types.
*
* @return the return type of methods of this type.
*/
public Type getReturnType() {
return getReturnType(getDescriptor());
}
/**
* Returns the size of the arguments and of the return value of methods of this type. This method
* should only be used for method types.
*
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
}
// -----------------------------------------------------------------------------------------------
// Conversion to type descriptors
// -----------------------------------------------------------------------------------------------
/** /**
* Returns the descriptor corresponding to this type. * Returns the descriptor corresponding to this type.
* *
@ -590,6 +518,34 @@ public class Type {
} }
} }
/**
* Returns the descriptor corresponding to the given class.
*
* @param clazz an object class, a primitive class or an array class.
* @return the descriptor corresponding to the given class.
*/
public static String getDescriptor(final Class<?> clazz) {
StringBuilder stringBuilder = new StringBuilder();
appendDescriptor(clazz, stringBuilder);
return stringBuilder.toString();
}
/**
* Returns the descriptor corresponding to the given constructor.
*
* @param constructor a {@link Constructor} object.
* @return the descriptor of the given constructor.
*/
public static String getConstructorDescriptor(final Constructor<?> constructor) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
Class<?>[] parameters = constructor.getParameterTypes();
for (int i = 0; i < parameters.length; ++i) {
appendDescriptor(parameters[i], stringBuilder);
}
return stringBuilder.append(")V").toString();
}
/** /**
* Returns the descriptor corresponding to the given argument and return types. * Returns the descriptor corresponding to the given argument and return types.
* *
@ -608,6 +564,24 @@ public class Type {
return stringBuilder.toString(); return stringBuilder.toString();
} }
/**
* Returns the descriptor corresponding to the given method.
*
* @param method a {@link Method} object.
* @return the descriptor of the given method.
*/
public static String getMethodDescriptor(final Method method) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; ++i) {
appendDescriptor(parameters[i], stringBuilder);
}
stringBuilder.append(')');
appendDescriptor(method.getReturnType(), stringBuilder);
return stringBuilder.toString();
}
/** /**
* Appends the descriptor corresponding to this type to the given string buffer. * Appends the descriptor corresponding to this type to the given string buffer.
* *
@ -625,75 +599,13 @@ public class Type {
} }
} }
// -----------------------------------------------------------------------------------------------
// Direct conversion from classes to type descriptors,
// without intermediate Type objects
// -----------------------------------------------------------------------------------------------
/**
* Returns the internal name of the given class. The internal name of a class is its fully
* qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
*
* @param clazz an object or array class.
* @return the internal name of the given class.
*/
public static String getInternalName(final Class<?> clazz) {
return clazz.getName().replace('.', '/');
}
/**
* Returns the descriptor corresponding to the given class.
*
* @param clazz an object class, a primitive class or an array class.
* @return the descriptor corresponding to the given class.
*/
public static String getDescriptor(final Class<?> clazz) {
StringBuilder stringBuilder = new StringBuilder();
appendDescriptor(stringBuilder, clazz);
return stringBuilder.toString();
}
/**
* Returns the descriptor corresponding to the given constructor.
*
* @param constructor a {@link Constructor} object.
* @return the descriptor of the given constructor.
*/
public static String getConstructorDescriptor(final Constructor<?> constructor) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
Class<?>[] parameters = constructor.getParameterTypes();
for (int i = 0; i < parameters.length; ++i) {
appendDescriptor(stringBuilder, parameters[i]);
}
return stringBuilder.append(")V").toString();
}
/**
* Returns the descriptor corresponding to the given method.
*
* @param method a {@link Method} object.
* @return the descriptor of the given method.
*/
public static String getMethodDescriptor(final Method method) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; ++i) {
appendDescriptor(stringBuilder, parameters[i]);
}
stringBuilder.append(')');
appendDescriptor(stringBuilder, method.getReturnType());
return stringBuilder.toString();
}
/** /**
* Appends the descriptor of the given class to the given string builder. * Appends the descriptor of the given class to the given string builder.
* *
* @param stringBuilder the string builder to which the descriptor must be appended.
* @param clazz the class whose descriptor must be computed. * @param clazz the class whose descriptor must be computed.
* @param stringBuilder the string builder to which the descriptor must be appended.
*/ */
private static void appendDescriptor(final StringBuilder stringBuilder, final Class<?> clazz) { private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) {
Class<?> currentClass = clazz; Class<?> currentClass = clazz;
while (currentClass.isArray()) { while (currentClass.isArray()) {
stringBuilder.append('['); stringBuilder.append('[');
@ -736,9 +648,34 @@ public class Type {
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Corresponding size and opcodes // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor.
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
/**
* Returns the sort of this type.
*
* @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
* #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
* {@link #METHOD}.
*/
public int getSort() {
return sort == INTERNAL ? OBJECT : sort;
}
/**
* Returns the number of dimensions of this array type. This method should only be used for an
* array type.
*
* @return the number of dimensions of this array type.
*/
public int getDimensions() {
int numDimensions = 1;
while (valueBuffer.charAt(valueBegin + numDimensions) == '[') {
numDimensions++;
}
return numDimensions;
}
/** /**
* Returns the size of values of this type. This method must not be used for method types. * Returns the size of values of this type. This method must not be used for method types.
* *
@ -767,6 +704,60 @@ public class Type {
} }
} }
/**
* Returns the size of the arguments and of the return value of methods of this type. This method
* should only be used for method types.
*
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
}
/**
* Computes the size of the arguments and of the return value of a method.
*
* @param methodDescriptor a method descriptor.
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
int argumentsSize = 1;
// Skip the first character, which is always a '('.
int currentOffset = 1;
int currentChar = methodDescriptor.charAt(currentOffset);
// Parse the argument types and compute their size, one at a each loop iteration.
while (currentChar != ')') {
if (currentChar == 'J' || currentChar == 'D') {
currentOffset++;
argumentsSize += 2;
} else {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
while (methodDescriptor.charAt(currentOffset++) != ';') {
// Skip the argument descriptor content.
}
}
argumentsSize += 1;
}
currentChar = methodDescriptor.charAt(currentOffset);
}
currentChar = methodDescriptor.charAt(currentOffset + 1);
if (currentChar == 'V') {
return argumentsSize << 2;
} else {
int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1;
return argumentsSize << 2 | returnSize;
}
}
/** /**
* Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for
* method types. * method types.
@ -841,7 +832,7 @@ public class Type {
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Equals, hashCode and toString // Equals, hashCode and toString.
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
/** /**