in src/main/java/com/amazon/corretto/hotpatch/org/objectweb/asm/ClassReader.java [441:749]
public void accept(
final ClassVisitor classVisitor,
final Attribute[] attributePrototypes,
final int parsingOptions) {
Context context = new Context();
context.attributePrototypes = attributePrototypes;
context.parsingOptions = parsingOptions;
context.charBuffer = new char[maxStringLength];
// Read the access_flags, this_class, super_class, interface_count and interfaces fields.
char[] charBuffer = context.charBuffer;
int currentOffset = header;
int accessFlags = readUnsignedShort(currentOffset);
String thisClass = readClass(currentOffset + 2, charBuffer);
String superClass = readClass(currentOffset + 4, charBuffer);
String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
currentOffset += 8;
for (int i = 0; i < interfaces.length; ++i) {
interfaces[i] = readClass(currentOffset, charBuffer);
currentOffset += 2;
}
// Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
// Attribute offsets exclude the attribute_name_index and attribute_length fields.
// - The offset of the InnerClasses attribute, or 0.
int innerClassesOffset = 0;
// - The offset of the EnclosingMethod attribute, or 0.
int enclosingMethodOffset = 0;
// - The string corresponding to the Signature attribute, or null.
String signature = null;
// - The string corresponding to the SourceFile attribute, or null.
String sourceFile = null;
// - The string corresponding to the SourceDebugExtension attribute, or null.
String sourceDebugExtension = null;
// - The offset of the RuntimeVisibleAnnotations attribute, or 0.
int runtimeVisibleAnnotationsOffset = 0;
// - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
int runtimeInvisibleAnnotationsOffset = 0;
// - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
int runtimeVisibleTypeAnnotationsOffset = 0;
// - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
int runtimeInvisibleTypeAnnotationsOffset = 0;
// - The offset of the Module attribute, or 0.
int moduleOffset = 0;
// - The offset of the ModulePackages attribute, or 0.
int modulePackagesOffset = 0;
// - The string corresponding to the ModuleMainClass attribute, or null.
String moduleMainClass = null;
// - The string corresponding to the NestHost attribute, or null.
String nestHostClass = null;
// - The offset of the NestMembers attribute, or 0.
int nestMembersOffset = 0;
// - The offset of the PermittedSubclasses attribute, or 0
int permittedSubclassesOffset = 0;
// - The offset of the Record attribute, or 0.
int recordOffset = 0;
// - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
// This list in the <i>reverse order</i> or their order in the ClassFile structure.
Attribute attributes = null;
int currentAttributeOffset = getFirstAttributeOffset();
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, charBuffer);
int attributeLength = readInt(currentAttributeOffset + 2);
currentAttributeOffset += 6;
// The tests are sorted in decreasing frequency order (based on frequencies observed on
// typical classes).
if (Constants.SOURCE_FILE.equals(attributeName)) {
sourceFile = readUTF8(currentAttributeOffset, charBuffer);
} else if (Constants.INNER_CLASSES.equals(attributeName)) {
innerClassesOffset = currentAttributeOffset;
} else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
enclosingMethodOffset = currentAttributeOffset;
} else if (Constants.NEST_HOST.equals(attributeName)) {
nestHostClass = readClass(currentAttributeOffset, charBuffer);
} else if (Constants.NEST_MEMBERS.equals(attributeName)) {
nestMembersOffset = currentAttributeOffset;
} else if (Constants.PERMITTED_SUBCLASSES.equals(attributeName)) {
permittedSubclassesOffset = currentAttributeOffset;
} else if (Constants.SIGNATURE.equals(attributeName)) {
signature = readUTF8(currentAttributeOffset, charBuffer);
} else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
runtimeVisibleAnnotationsOffset = currentAttributeOffset;
} else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
} else if (Constants.DEPRECATED.equals(attributeName)) {
accessFlags |= Opcodes.ACC_DEPRECATED;
} else if (Constants.SYNTHETIC.equals(attributeName)) {
accessFlags |= Opcodes.ACC_SYNTHETIC;
} else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
if (attributeLength > classFileBuffer.length - currentAttributeOffset) {
throw new IllegalArgumentException();
}
sourceDebugExtension =
readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
} else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
} else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
} else if (Constants.RECORD.equals(attributeName)) {
recordOffset = currentAttributeOffset;
accessFlags |= Opcodes.ACC_RECORD;
} else if (Constants.MODULE.equals(attributeName)) {
moduleOffset = currentAttributeOffset;
} else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
moduleMainClass = readClass(currentAttributeOffset, charBuffer);
} else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
modulePackagesOffset = currentAttributeOffset;
} else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// The BootstrapMethods attribute is read in the constructor.
Attribute attribute =
readAttribute(
attributePrototypes,
attributeName,
currentAttributeOffset,
attributeLength,
charBuffer,
-1,
null);
attribute.nextAttribute = attributes;
attributes = attribute;
}
currentAttributeOffset += attributeLength;
}
// Visit the class declaration. The minor_version and major_version fields start 6 bytes before
// the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
classVisitor.visit(
readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
// Visit the SourceFile and SourceDebugExtenstion attributes.
if ((parsingOptions & SKIP_DEBUG) == 0
&& (sourceFile != null || sourceDebugExtension != null)) {
classVisitor.visitSource(sourceFile, sourceDebugExtension);
}
// Visit the Module, ModulePackages and ModuleMainClass attributes.
if (moduleOffset != 0) {
readModuleAttributes(
classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
}
// Visit the NestHost attribute.
if (nestHostClass != null) {
classVisitor.visitNestHost(nestHostClass);
}
// Visit the EnclosingMethod attribute.
if (enclosingMethodOffset != 0) {
String className = readClass(enclosingMethodOffset, charBuffer);
int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
classVisitor.visitOuterClass(className, name, type);
}
// Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleAnnotations attribute.
if (runtimeInvisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeVisibleTypeAnnotations attribute.
if (runtimeVisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleTypeAnnotations attribute.
if (runtimeInvisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the non standard attributes.
while (attributes != null) {
// Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
Attribute nextAttribute = attributes.nextAttribute;
attributes.nextAttribute = null;
classVisitor.visitAttribute(attributes);
attributes = nextAttribute;
}
// Visit the NestedMembers attribute.
if (nestMembersOffset != 0) {
int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
int currentNestMemberOffset = nestMembersOffset + 2;
while (numberOfNestMembers-- > 0) {
classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
currentNestMemberOffset += 2;
}
}
// Visit the PermittedSubclasses attribute.
if (permittedSubclassesOffset != 0) {
int numberOfPermittedSubclasses = readUnsignedShort(permittedSubclassesOffset);
int currentPermittedSubclassesOffset = permittedSubclassesOffset + 2;
while (numberOfPermittedSubclasses-- > 0) {
classVisitor.visitPermittedSubclass(
readClass(currentPermittedSubclassesOffset, charBuffer));
currentPermittedSubclassesOffset += 2;
}
}
// Visit the InnerClasses attribute.
if (innerClassesOffset != 0) {
int numberOfClasses = readUnsignedShort(innerClassesOffset);
int currentClassesOffset = innerClassesOffset + 2;
while (numberOfClasses-- > 0) {
classVisitor.visitInnerClass(
readClass(currentClassesOffset, charBuffer),
readClass(currentClassesOffset + 2, charBuffer),
readUTF8(currentClassesOffset + 4, charBuffer),
readUnsignedShort(currentClassesOffset + 6));
currentClassesOffset += 8;
}
}
// Visit Record components.
if (recordOffset != 0) {
int recordComponentsCount = readUnsignedShort(recordOffset);
recordOffset += 2;
while (recordComponentsCount-- > 0) {
recordOffset = readRecordComponent(classVisitor, context, recordOffset);
}
}
// Visit the fields and methods.
int fieldsCount = readUnsignedShort(currentOffset);
currentOffset += 2;
while (fieldsCount-- > 0) {
currentOffset = readField(classVisitor, context, currentOffset);
}
int methodsCount = readUnsignedShort(currentOffset);
currentOffset += 2;
while (methodsCount-- > 0) {
currentOffset = readMethod(classVisitor, context, currentOffset);
}
// Visit the end of the class.
classVisitor.visitEnd();
}