Upgrade to ASM 9.7.1

Closes gh-33821
This commit is contained in:
Juergen Hoeller 2024-10-30 16:44:47 +01:00
parent e23c8bfbb6
commit 864cb25eec
7 changed files with 215 additions and 39 deletions

View File

@ -44,11 +44,11 @@ public class Attribute {
public final String type; public final String type;
/** /**
* The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}). * The raw content of this attribute, as returned by {@link
* The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i> * #write(ClassWriter,byte[],int,int,int)}. The 6 header bytes of the attribute
* included. * (attribute_name_index and attribute_length) are <i>not</i> included.
*/ */
private byte[] content; private ByteVector cachedContent;
/** /**
* The next attribute in this attribute list (Attribute instances can be linked via this field to * The next attribute in this attribute list (Attribute instances can be linked via this field to
@ -93,7 +93,9 @@ public class Attribute {
* *
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
* a Code attribute that contains labels. * a Code attribute that contains labels.
* @deprecated no longer used by ASM.
*/ */
@Deprecated
protected Label[] getLabels() { protected Label[] getLabels() {
return new Label[0]; return new Label[0];
} }
@ -115,7 +117,9 @@ public class Attribute {
* attribute header bytes (attribute_name_index and attribute_length) are not taken into * attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here. * account here.
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
* is not a Code attribute. * is not a Code attribute. Labels defined in the attribute must be created and added to this
* array, if not already present, by calling the {@link #readLabel} method (do not create
* {@link Label} instances directly).
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes. * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
*/ */
protected Attribute read( protected Attribute read(
@ -126,16 +130,99 @@ public class Attribute {
final int codeAttributeOffset, final int codeAttributeOffset,
final Label[] labels) { final Label[] labels) {
Attribute attribute = new Attribute(type); Attribute attribute = new Attribute(type);
attribute.content = new byte[length]; attribute.cachedContent = new ByteVector(classReader.readBytes(offset, length));
System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
return attribute; return attribute;
} }
/**
* Reads an attribute with the same {@link #type} as the given attribute. This method returns a
* new {@link Attribute} object, corresponding to the 'length' bytes starting at 'offset', in the
* given ClassReader.
*
* @param attribute The attribute prototype that is used for reading.
* @param classReader the class that contains the attribute to be read.
* @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here.
* @param length the length of the attribute's content (excluding the 6 attribute header bytes).
* @param charBuffer the buffer to be used to call the ClassReader methods requiring a
* 'charBuffer' parameter.
* @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
* in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here.
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read
* is not a Code attribute. Labels defined in the attribute are added to this array, if not
* already present.
* @return a new {@link Attribute} object corresponding to the specified bytes.
*/
public static Attribute read(
final Attribute attribute,
final ClassReader classReader,
final int offset,
final int length,
final char[] charBuffer,
final int codeAttributeOffset,
final Label[] labels) {
return attribute.read(classReader, offset, length, charBuffer, codeAttributeOffset, labels);
}
/**
* Returns the label corresponding to the given bytecode offset by calling {@link
* ClassReader#readLabel}. This creates and adds the label to the given array if it is not already
* present. Note that this created label may be a {@link Label} subclass instance, if the given
* ClassReader overrides {@link ClassReader#readLabel}. Hence {@link #read(ClassReader, int, int,
* char[], int, Label[])} must not manually create {@link Label} instances.
*
* @param bytecodeOffset a bytecode offset in a method.
* @param labels the already created labels, indexed by their offset. If a label already exists
* for bytecodeOffset this method does not create a new one. Otherwise it stores the new label
* in this array.
* @return a label for the given bytecode offset.
*/
public static Label readLabel(
final ClassReader classReader, final int bytecodeOffset, final Label[] labels) {
return classReader.readLabel(bytecodeOffset, labels);
}
/**
* Calls {@link #write(ClassWriter,byte[],int,int,int)} if it has not already been called and
* returns its result or its (cached) previous result.
*
* @param classWriter the class to which this attribute must be added. This parameter can be used
* to add the items that corresponds to this attribute to the constant pool of this class.
* @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
* if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
* attribute.
* @param codeLength the length of the bytecode of the method corresponding to this code
* attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
* field of the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
* -1 if this attribute is not a Code attribute.
* @param maxLocals the maximum number of local variables of the method corresponding to this code
* attribute, or -1 if this attribute is not a Code attribute.
* @return the byte array form of this attribute.
*/
private ByteVector maybeWrite(
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
if (cachedContent == null) {
cachedContent = write(classWriter, code, codeLength, maxStack, maxLocals);
}
return cachedContent;
}
/** /**
* Returns the byte array form of the content of this attribute. The 6 header bytes * Returns the byte array form of the content of this attribute. The 6 header bytes
* (attribute_name_index and attribute_length) must <i>not</i> be added in the returned * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
* ByteVector. * ByteVector.
* *
* <p>This method is only invoked once to compute the binary form of this attribute. Subsequent
* changes to the attribute after it was written for the first time will not be considered.
*
* @param classWriter the class to which this attribute must be added. This parameter can be used * @param classWriter the class to which this attribute must be added. This parameter can be used
* to add the items that corresponds to this attribute to the constant pool of this class. * to add the items that corresponds to this attribute to the constant pool of this class.
* @param code the bytecode of the method corresponding to this Code attribute, or {@literal null} * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
@ -156,7 +243,39 @@ public class Attribute {
final int codeLength, final int codeLength,
final int maxStack, final int maxStack,
final int maxLocals) { final int maxLocals) {
return new ByteVector(content); return cachedContent;
}
/**
* Returns the byte array form of the content of the given attribute. The 6 header bytes
* (attribute_name_index and attribute_length) are <i>not</i> added in the returned byte array.
*
* @param attribute The attribute that should be written.
* @param classWriter the class to which this attribute must be added. This parameter can be used
* to add the items that corresponds to this attribute to the constant pool of this class.
* @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
* if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
* attribute.
* @param codeLength the length of the bytecode of the method corresponding to this code
* attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
* field of the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
* -1 if this attribute is not a Code attribute.
* @param maxLocals the maximum number of local variables of the method corresponding to this code
* attribute, or -1 if this attribute is not a Code attribute.
* @return the byte array form of this attribute.
*/
public static byte[] write(
final Attribute attribute,
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
ByteVector content = attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals);
byte[] result = new byte[content.length];
System.arraycopy(content.data, 0, result, 0, content.length);
return result;
} }
/** /**
@ -221,7 +340,7 @@ public class Attribute {
Attribute attribute = this; Attribute attribute = this;
while (attribute != null) { while (attribute != null) {
symbolTable.addConstantUtf8(attribute.type); symbolTable.addConstantUtf8(attribute.type);
size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length; size += 6 + attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals).length;
attribute = attribute.nextAttribute; attribute = attribute.nextAttribute;
} }
return size; return size;
@ -308,7 +427,7 @@ public class Attribute {
Attribute attribute = this; Attribute attribute = this;
while (attribute != null) { while (attribute != null) {
ByteVector attributeContent = ByteVector attributeContent =
attribute.write(classWriter, code, codeLength, maxStack, maxLocals); attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals);
// Put attribute_name_index and attribute_length. // Put attribute_name_index and attribute_length.
output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length); output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
output.putByteArray(attributeContent.data, 0, attributeContent.length); output.putByteArray(attributeContent.data, 0, attributeContent.length);

View File

@ -188,13 +188,14 @@ public class ClassReader {
* @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
* @param checkClassVersion whether to check the class version or not. * @param checkClassVersion whether to check the class version or not.
*/ */
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
ClassReader( ClassReader(
final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
this.classFileBuffer = classFileBuffer; this.classFileBuffer = classFileBuffer;
this.b = classFileBuffer; this.b = classFileBuffer;
// Check the class' major_version. This field is after the magic and minor_version fields, which // Check the class' major_version. This field is after the magic and minor_version fields, which
// use 4 and 2 bytes respectively. // use 4 and 2 bytes respectively.
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V23) { if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Unsupported class file major version " + readShort(classFileOffset + 6)); "Unsupported class file major version " + readShort(classFileOffset + 6));
} }
@ -340,7 +341,7 @@ public class ClassReader {
private static int computeBufferSize(final InputStream inputStream) throws IOException { private static int computeBufferSize(final InputStream inputStream) throws IOException {
int expectedLength = inputStream.available(); int expectedLength = inputStream.available();
/* /*
* Some implementations can return 0 while holding available data (for example, new * Some implementations can return 0 while holding available data (e.g. new
* FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might * FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might
* be returned, and in this case we use a default size. * be returned, and in this case we use a default size.
*/ */
@ -2311,7 +2312,7 @@ public class ClassReader {
{ {
// A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO
// with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:...,
// where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (for example, IFNE for ASM_IFEQ) and // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and
// where <L> designates the instruction just after the GOTO_W. // where <L> designates the instruction just after the GOTO_W.
// First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and
// ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL.
@ -3603,6 +3604,20 @@ public class ClassReader {
return classFileBuffer[offset] & 0xFF; return classFileBuffer[offset] & 0xFF;
} }
/**
* Reads several bytes in this {@link ClassReader}. <i>This method is intended for {@link
* Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param offset the start offset of the bytes to be read in this {@link ClassReader}.
* @param length the number of bytes to read.
* @return the read bytes.
*/
public byte[] readBytes(final int offset, final int length) {
byte[] result = new byte[length];
System.arraycopy(classFileBuffer, offset, result, 0, length);
return result;
}
/** /**
* Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for * Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for
* {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i> * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>

View File

@ -264,13 +264,7 @@ public class ClassWriter extends ClassVisitor {
super(/* latest api = */ Opcodes.ASM9); super(/* latest api = */ Opcodes.ASM9);
this.flags = flags; this.flags = flags;
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
if ((flags & COMPUTE_FRAMES) != 0) { setFlags(flags);
compute = MethodWriter.COMPUTE_ALL_FRAMES;
} else if ((flags & COMPUTE_MAXS) != 0) {
compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
} else {
compute = MethodWriter.COMPUTE_NOTHING;
}
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -1020,6 +1014,28 @@ public class ClassWriter extends ClassVisitor {
return symbolTable.addConstantNameAndType(name, descriptor); return symbolTable.addConstantNameAndType(name, descriptor);
} }
/**
* Changes the computation strategy of method properties like max stack size, max number of local
* variables, and frames.
*
* <p><b>WARNING</b>: {@link #setFlags(int)} method changes the behavior of new method visitors
* returned from {@link #visitMethod(int, String, String, String, String[])}. The behavior will be
* changed only after the next method visitor is returned. All the previously returned method
* visitors keep their previous behavior.
*
* @param flags option flags that can be used to modify the default behavior of this class. Must
* be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
*/
public final void setFlags(final int flags) {
if ((flags & ClassWriter.COMPUTE_FRAMES) != 0) {
compute = MethodWriter.COMPUTE_ALL_FRAMES;
} else if ((flags & ClassWriter.COMPUTE_MAXS) != 0) {
compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
} else {
compute = MethodWriter.COMPUTE_NOTHING;
}
}
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// Default method to compute common super classes when computing stack map frames // Default method to compute common super classes when computing stack map frames
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------

View File

@ -30,19 +30,20 @@ package org.springframework.asm;
/** /**
* A visitor to visit a Java method. The methods of this class must be called in the following * A visitor to visit a Java method. The methods of this class must be called in the following
* order: ( {@code visitParameter} )* [ {@code visitAnnotationDefault} ] ( {@code visitAnnotation} | * order: ( {@code visitParameter} )* [ {@code visitAnnotationDefault} ] ( {@code visitAnnotation} |
* {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} {@code * {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} | {@code
* visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} | * visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} |
* {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code * {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code
* visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code * visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code
* visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}. * visitLocalVariableAnnotation} | {@code visitLineNumber} | {@code visitAttribute} )* {@code
* In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel} methods must be called in the * visitMaxs} ] {@code visitEnd}. In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel}
* sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation} * methods must be called in the sequential order of the bytecode instructions of the visited code,
* must be called <i>after</i> the annotated instruction, {@code visitTryCatchBlock} must be called * {@code visitInsnAnnotation} must be called <i>after</i> the annotated instruction, {@code
* <i>before</i> the labels passed as arguments have been visited, {@code * visitTryCatchBlock} must be called <i>before</i> the labels passed as arguments have been
* visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try catch block has * visited, {@code visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try
* been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code * catch block has been visited, and the {@code visitLocalVariable}, {@code
* visitLineNumber} methods must be called <i>after</i> the labels passed as arguments have been * visitLocalVariableAnnotation} and {@code visitLineNumber} methods must be called <i>after</i> the
* visited. * labels passed as arguments have been visited. Finally, the {@code visitAttribute} method must be
* called before {@code visitCode} for non-code attributes, and after it for code attributes.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */

View File

@ -288,6 +288,7 @@ public interface Opcodes {
int V21 = 0 << 16 | 65; int V21 = 0 << 16 | 65;
int V22 = 0 << 16 | 66; int V22 = 0 << 16 | 66;
int V23 = 0 << 16 | 67; int V23 = 0 << 16 | 67;
int V24 = 0 << 16 | 68;
/** /**
* Version flag indicating that the class is using 'preview' features. * Version flag indicating that the class is using 'preview' features.

View File

@ -178,7 +178,9 @@ abstract class Symbol {
* <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link * <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
* #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG}, * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
* <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link * <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
* #CONSTANT_METHOD_HANDLE_TAG} symbols, * #CONSTANT_METHOD_HANDLE_TAG} symbols (or this value left shifted by 8 bits for
* reference_kind values larger than or equal to H_INVOKEVIRTUAL and if the method owner is
* an interface),
* <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link * <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
* <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for * <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for

View File

@ -221,7 +221,9 @@ final class SymbolTable {
classReader.readByte(itemOffset), classReader.readByte(itemOffset),
classReader.readClass(memberRefItemOffset, charBuffer), classReader.readClass(memberRefItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset, charBuffer), classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
classReader.readByte(memberRefItemOffset - 1)
== Symbol.CONSTANT_INTERFACE_METHODREF_TAG);
break; break;
case Symbol.CONSTANT_DYNAMIC_TAG: case Symbol.CONSTANT_DYNAMIC_TAG:
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
@ -830,14 +832,15 @@ final class SymbolTable {
final String descriptor, final String descriptor,
final boolean isInterface) { final boolean isInterface) {
final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
final int data = getConstantMethodHandleSymbolData(referenceKind, isInterface);
// Note that we don't need to include isInterface in the hash computation, because it is // Note that we don't need to include isInterface in the hash computation, because it is
// redundant with owner (we can't have the same owner with different isInterface values). // redundant with owner (we can't have the same owner with different isInterface values).
int hashCode = hash(tag, owner, name, descriptor, referenceKind); int hashCode = hash(tag, owner, name, descriptor, data);
Entry entry = get(hashCode); Entry entry = get(hashCode);
while (entry != null) { while (entry != null) {
if (entry.tag == tag if (entry.tag == tag
&& entry.hashCode == hashCode && entry.hashCode == hashCode
&& entry.data == referenceKind && entry.data == data
&& entry.owner.equals(owner) && entry.owner.equals(owner)
&& entry.name.equals(name) && entry.name.equals(name)
&& entry.value.equals(descriptor)) { && entry.value.equals(descriptor)) {
@ -851,8 +854,7 @@ final class SymbolTable {
constantPool.put112( constantPool.put112(
tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index); tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
} }
return put( return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, data, hashCode));
new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
} }
/** /**
@ -866,16 +868,36 @@ final class SymbolTable {
* @param owner the internal name of a class of interface. * @param owner the internal name of a class of interface.
* @param name a field or method name. * @param name a field or method name.
* @param descriptor a field or method descriptor. * @param descriptor a field or method descriptor.
* @param isInterface whether owner is an interface or not.
*/ */
private void addConstantMethodHandle( private void addConstantMethodHandle(
final int index, final int index,
final int referenceKind, final int referenceKind,
final String owner, final String owner,
final String name, final String name,
final String descriptor) { final String descriptor,
final boolean isInterface) {
final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
int hashCode = hash(tag, owner, name, descriptor, referenceKind); final int data = getConstantMethodHandleSymbolData(referenceKind, isInterface);
add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode)); int hashCode = hash(tag, owner, name, descriptor, data);
add(new Entry(index, tag, owner, name, descriptor, data, hashCode));
}
/**
* Returns the {@link Symbol#data} field for a CONSTANT_MethodHandle_info Symbol.
*
* @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
* Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
* Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
* Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param isInterface whether owner is an interface or not.
*/
private static int getConstantMethodHandleSymbolData(
final int referenceKind, final boolean isInterface) {
if (referenceKind > Opcodes.H_PUTSTATIC && isInterface) {
return referenceKind << 8;
}
return referenceKind;
} }
/** /**