parent
e23c8bfbb6
commit
864cb25eec
|
@ -44,11 +44,11 @@ public class Attribute {
|
|||
public final String type;
|
||||
|
||||
/**
|
||||
* The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
|
||||
* The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
|
||||
* included.
|
||||
* The raw content of this attribute, as returned by {@link
|
||||
* #write(ClassWriter,byte[],int,int,int)}. The 6 header bytes of the attribute
|
||||
* (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
|
||||
|
@ -93,7 +93,9 @@ public class Attribute {
|
|||
*
|
||||
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
|
||||
* a Code attribute that contains labels.
|
||||
* @deprecated no longer used by ASM.
|
||||
*/
|
||||
@Deprecated
|
||||
protected Label[] getLabels() {
|
||||
return new Label[0];
|
||||
}
|
||||
|
@ -115,7 +117,9 @@ public class Attribute {
|
|||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
protected Attribute read(
|
||||
|
@ -126,16 +130,99 @@ public class Attribute {
|
|||
final int codeAttributeOffset,
|
||||
final Label[] labels) {
|
||||
Attribute attribute = new Attribute(type);
|
||||
attribute.content = new byte[length];
|
||||
System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
|
||||
attribute.cachedContent = new ByteVector(classReader.readBytes(offset, length));
|
||||
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
|
||||
* (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
|
||||
* 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
|
||||
* 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}
|
||||
|
@ -156,7 +243,39 @@ public class Attribute {
|
|||
final int codeLength,
|
||||
final int maxStack,
|
||||
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;
|
||||
while (attribute != null) {
|
||||
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;
|
||||
}
|
||||
return size;
|
||||
|
@ -308,7 +427,7 @@ public class Attribute {
|
|||
Attribute attribute = this;
|
||||
while (attribute != null) {
|
||||
ByteVector attributeContent =
|
||||
attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
|
||||
attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals);
|
||||
// Put attribute_name_index and attribute_length.
|
||||
output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
|
||||
output.putByteArray(attributeContent.data, 0, attributeContent.length);
|
||||
|
|
|
@ -188,13 +188,14 @@ public class ClassReader {
|
|||
* @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.
|
||||
*/
|
||||
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
|
||||
ClassReader(
|
||||
final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
|
||||
this.classFileBuffer = classFileBuffer;
|
||||
this.b = classFileBuffer;
|
||||
// Check the class' major_version. This field is after the magic and minor_version fields, which
|
||||
// use 4 and 2 bytes respectively.
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V23) {
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported class file major version " + readShort(classFileOffset + 6));
|
||||
}
|
||||
|
@ -340,7 +341,7 @@ public class ClassReader {
|
|||
private static int computeBufferSize(final InputStream inputStream) throws IOException {
|
||||
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
|
||||
* 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
|
||||
// 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.
|
||||
// First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and
|
||||
// ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL.
|
||||
|
@ -3603,6 +3604,20 @@ public class ClassReader {
|
|||
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
|
||||
* {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
|
||||
|
|
|
@ -264,13 +264,7 @@ public class ClassWriter extends ClassVisitor {
|
|||
super(/* latest api = */ Opcodes.ASM9);
|
||||
this.flags = flags;
|
||||
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
|
||||
if ((flags & COMPUTE_FRAMES) != 0) {
|
||||
compute = MethodWriter.COMPUTE_ALL_FRAMES;
|
||||
} else if ((flags & COMPUTE_MAXS) != 0) {
|
||||
compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
|
||||
} else {
|
||||
compute = MethodWriter.COMPUTE_NOTHING;
|
||||
}
|
||||
setFlags(flags);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
@ -1020,6 +1014,28 @@ public class ClassWriter extends ClassVisitor {
|
|||
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
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
* order: ( {@code visitParameter} )* [ {@code visitAnnotationDefault} ] ( {@code visitAnnotation} |
|
||||
* {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} {@code
|
||||
* {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} | {@code
|
||||
* visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} |
|
||||
* {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code
|
||||
* visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code
|
||||
* visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}.
|
||||
* In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel} methods must be called in the
|
||||
* sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation}
|
||||
* must be called <i>after</i> the annotated instruction, {@code visitTryCatchBlock} must be called
|
||||
* <i>before</i> the labels passed as arguments have been visited, {@code
|
||||
* visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try catch block has
|
||||
* been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code
|
||||
* visitLineNumber} methods must be called <i>after</i> the labels passed as arguments have been
|
||||
* visited.
|
||||
* visitLocalVariableAnnotation} | {@code visitLineNumber} | {@code visitAttribute} )* {@code
|
||||
* visitMaxs} ] {@code visitEnd}. In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel}
|
||||
* methods must be called in the sequential order of the bytecode instructions of the visited code,
|
||||
* {@code visitInsnAnnotation} must be called <i>after</i> the annotated instruction, {@code
|
||||
* visitTryCatchBlock} must be called <i>before</i> the labels passed as arguments have been
|
||||
* visited, {@code visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try
|
||||
* catch block has been visited, and the {@code visitLocalVariable}, {@code
|
||||
* visitLocalVariableAnnotation} and {@code visitLineNumber} methods must be called <i>after</i> the
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -288,6 +288,7 @@ public interface Opcodes {
|
|||
int V21 = 0 << 16 | 65;
|
||||
int V22 = 0 << 16 | 66;
|
||||
int V23 = 0 << 16 | 67;
|
||||
int V24 = 0 << 16 | 68;
|
||||
|
||||
/**
|
||||
* Version flag indicating that the class is using 'preview' features.
|
||||
|
|
|
@ -178,7 +178,9 @@ abstract class Symbol {
|
|||
* <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
|
||||
* #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
|
||||
* <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
|
||||
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
|
||||
* <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for
|
||||
|
|
|
@ -221,7 +221,9 @@ final class SymbolTable {
|
|||
classReader.readByte(itemOffset),
|
||||
classReader.readClass(memberRefItemOffset, 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;
|
||||
case Symbol.CONSTANT_DYNAMIC_TAG:
|
||||
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
|
||||
|
@ -830,14 +832,15 @@ final class SymbolTable {
|
|||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
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
|
||||
// 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);
|
||||
while (entry != null) {
|
||||
if (entry.tag == tag
|
||||
&& entry.hashCode == hashCode
|
||||
&& entry.data == referenceKind
|
||||
&& entry.data == data
|
||||
&& entry.owner.equals(owner)
|
||||
&& entry.name.equals(name)
|
||||
&& entry.value.equals(descriptor)) {
|
||||
|
@ -851,8 +854,7 @@ final class SymbolTable {
|
|||
constantPool.put112(
|
||||
tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
|
||||
}
|
||||
return put(
|
||||
new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
|
||||
return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, data, hashCode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -866,16 +868,36 @@ final class SymbolTable {
|
|||
* @param owner the internal name of a class of interface.
|
||||
* @param name a field or method name.
|
||||
* @param descriptor a field or method descriptor.
|
||||
* @param isInterface whether owner is an interface or not.
|
||||
*/
|
||||
private void addConstantMethodHandle(
|
||||
final int index,
|
||||
final int referenceKind,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor) {
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
|
||||
int hashCode = hash(tag, owner, name, descriptor, referenceKind);
|
||||
add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
|
||||
final int data = getConstantMethodHandleSymbolData(referenceKind, isInterface);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue