".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
this.nameIndex = symbolTable.addConstantUtf8(name);
diff --git a/spring-core/src/main/java/org/springframework/asm/ModuleVisitor.java b/spring-core/src/main/java/org/springframework/asm/ModuleVisitor.java
index e8c2b062865..afdb37279f2 100644
--- a/spring-core/src/main/java/org/springframework/asm/ModuleVisitor.java
+++ b/spring-core/src/main/java/org/springframework/asm/ModuleVisitor.java
@@ -65,10 +65,18 @@ public abstract class ModuleVisitor {
* @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
* be null.
*/
+ @SuppressWarnings("deprecation")
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
- if (api != Opcodes.ASM7 && api != Opcodes.ASM6) {
+ if (api != Opcodes.ASM7
+ && api != Opcodes.ASM6
+ && api != Opcodes.ASM5
+ && api != Opcodes.ASM4
+ && api != Opcodes.ASM8_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
+ if (api == Opcodes.ASM8_EXPERIMENTAL) {
+ Constants.checkAsm8Experimental(this);
+ }
this.api = api;
this.mv = moduleVisitor;
}
diff --git a/spring-core/src/main/java/org/springframework/asm/ModuleWriter.java b/spring-core/src/main/java/org/springframework/asm/ModuleWriter.java
index 8a54e652df7..e23e28cac47 100644
--- a/spring-core/src/main/java/org/springframework/asm/ModuleWriter.java
+++ b/spring-core/src/main/java/org/springframework/asm/ModuleWriter.java
@@ -94,7 +94,7 @@ final class ModuleWriter extends ModuleVisitor {
private int mainClassIndex;
ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
- super(Opcodes.ASM7);
+ super(/* latest api = */ Opcodes.ASM7);
this.symbolTable = symbolTable;
this.moduleNameIndex = name;
this.moduleFlags = access;
diff --git a/spring-core/src/main/java/org/springframework/asm/Opcodes.java b/spring-core/src/main/java/org/springframework/asm/Opcodes.java
index 90bd930fcc3..21fa7287b21 100644
--- a/spring-core/src/main/java/org/springframework/asm/Opcodes.java
+++ b/spring-core/src/main/java/org/springframework/asm/Opcodes.java
@@ -48,6 +48,14 @@ public interface Opcodes {
int ASM6 = 6 << 16 | 0 << 8;
int ASM7 = 7 << 16 | 0 << 8;
+ /**
+ * Experimental, use at your own risk. This field will be renamed when it becomes stable, this
+ * will break existing code using it. Only code compiled with --enable-preview can use this.
+ *
+ * @deprecated This API is experimental.
+ */
+ @Deprecated int ASM8_EXPERIMENTAL = 1 << 24 | 8 << 16 | 0 << 8;
+
/*
* Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff
* method in API_OLD is deprecated and replaced with visitNewStuff in API_NEW, then the
@@ -270,6 +278,7 @@ public interface Opcodes {
int V12 = 0 << 16 | 56;
int V13 = 0 << 16 | 57;
int V14 = 0 << 16 | 58;
+ int V15 = 0 << 16 | 59;
/**
* Version flag indicating that the class is using 'preview' features.
@@ -306,7 +315,7 @@ public interface Opcodes {
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
- int ACC_MANDATED = 0x8000; // parameter, module, module *
+ int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific access flags.
diff --git a/spring-core/src/main/java/org/springframework/asm/RecordComponentVisitor.java b/spring-core/src/main/java/org/springframework/asm/RecordComponentVisitor.java
new file mode 100644
index 00000000000..4dfab5d1264
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/asm/RecordComponentVisitor.java
@@ -0,0 +1,169 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package org.springframework.asm;
+
+/**
+ * A visitor to visit a record component. The methods of this class must be called in the following
+ * order: ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
+ * visitEnd}.
+ *
+ * @author Remi Forax
+ * @author Eric Bruneton
+ * @deprecated this API is experimental.
+ */
+@Deprecated
+public abstract class RecordComponentVisitor {
+ /**
+ * The ASM API version implemented by this visitor. The value of this field must be {@link
+ * Opcodes#ASM8_EXPERIMENTAL}.
+ */
+ protected final int api;
+
+ /**
+ * The record visitor to which this visitor must delegate method calls. May be {@literal null}.
+ */
+ /*package-private*/ RecordComponentVisitor delegate;
+
+ /**
+ * Constructs a new {@link RecordComponentVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be {@link
+ * Opcodes#ASM8_EXPERIMENTAL}.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public RecordComponentVisitor(final int api) {
+ this(api, null);
+ }
+
+ /**
+ * Constructs a new {@link RecordComponentVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be {@link
+ * Opcodes#ASM8_EXPERIMENTAL}.
+ * @param recordComponentVisitor the record component visitor to which this visitor must delegate
+ * method calls. May be null.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public RecordComponentVisitor(
+ final int api, final RecordComponentVisitor recordComponentVisitor) {
+ if (api != Opcodes.ASM7
+ && api != Opcodes.ASM6
+ && api != Opcodes.ASM5
+ && api != Opcodes.ASM4
+ && api != Opcodes.ASM8_EXPERIMENTAL) {
+ throw new IllegalArgumentException("Unsupported api " + api);
+ }
+ if (api == Opcodes.ASM8_EXPERIMENTAL) {
+ Constants.checkAsm8Experimental(this);
+ }
+ this.api = api;
+ this.delegate = recordComponentVisitor;
+ }
+
+ /**
+ * The record visitor to which this visitor must delegate method calls. May be {@literal null}.
+ *
+ * @return the record visitor to which this visitor must delegate method calls or {@literal null}.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public RecordComponentVisitor getDelegateExperimental() {
+ return delegate;
+ }
+
+ /**
+ * Visits an annotation of the record component.
+ *
+ * @param descriptor the class descriptor of the annotation class.
+ * @param visible {@literal true} if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
+ * interested in visiting this annotation.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public AnnotationVisitor visitAnnotationExperimental(
+ final String descriptor, final boolean visible) {
+ if (delegate != null) {
+ return delegate.visitAnnotationExperimental(descriptor, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits an annotation on a type in the record component signature.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
+ * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
+ * {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+ * static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+ * 'typeRef' as a whole.
+ * @param descriptor the class descriptor of the annotation class.
+ * @param visible {@literal true} if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
+ * interested in visiting this annotation.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public AnnotationVisitor visitTypeAnnotationExperimental(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ if (delegate != null) {
+ return delegate.visitTypeAnnotationExperimental(typeRef, typePath, descriptor, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits a non standard attribute of the record component.
+ *
+ * @param attribute an attribute.
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public void visitAttributeExperimental(final Attribute attribute) {
+ if (delegate != null) {
+ delegate.visitAttributeExperimental(attribute);
+ }
+ }
+
+ /**
+ * Visits the end of the record component. This method, which is the last one to be called, is
+ * used to inform the visitor that everything have been visited.
+ *
+ * @deprecated this API is experimental.
+ */
+ @Deprecated
+ public void visitEndExperimental() {
+ if (delegate != null) {
+ delegate.visitEndExperimental();
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/asm/RecordComponentWriter.java b/spring-core/src/main/java/org/springframework/asm/RecordComponentWriter.java
new file mode 100644
index 00000000000..c775fc4bd8f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/asm/RecordComponentWriter.java
@@ -0,0 +1,242 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package org.springframework.asm;
+
+@SuppressWarnings("deprecation")
+final class RecordComponentWriter extends RecordComponentVisitor {
+ /** Where the constants used in this RecordComponentWriter must be stored. */
+ private final SymbolTable symbolTable;
+
+ // Note: fields are ordered as in the component_info structure, and those related to attributes
+ // are ordered as in Section TODO of the JVMS.
+ // The field accessFlag doesn't exist in the component_info structure but is used to carry
+ // ACC_DEPRECATED which is represented by an attribute in the structure and as an access flag by
+ // ASM.
+
+ /** The access_flags field can only be {@link Opcodes#ACC_DEPRECATED}. */
+ private final int accessFlags;
+
+ /** The name_index field of the Record attribute. */
+ private final int nameIndex;
+
+ /** The descriptor_index field of the the Record attribute. */
+ private final int descriptorIndex;
+
+ /**
+ * The signature_index field of the Signature attribute of this record component, or 0 if there is
+ * no Signature attribute.
+ */
+ private int signatureIndex;
+
+ /**
+ * The last runtime visible annotation of this record component. The previous ones can be accessed
+ * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+ */
+ private AnnotationWriter lastRuntimeVisibleAnnotation;
+
+ /**
+ * The last runtime invisible annotation of this record component. The previous ones can be
+ * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+ */
+ private AnnotationWriter lastRuntimeInvisibleAnnotation;
+
+ /**
+ * The last runtime visible type annotation of this record component. The previous ones can be
+ * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+ */
+ private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
+
+ /**
+ * The last runtime invisible type annotation of this record component. The previous ones can be
+ * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+ */
+ private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
+
+ /**
+ * The first non standard attribute of this record component. The next ones can be accessed with
+ * the {@link Attribute#nextAttribute} field. May be {@literal null}.
+ *
+ * WARNING: this list stores the attributes in the reverse order of their visit.
+ * firstAttribute is actually the last attribute visited in {@link
+ * #visitAttributeExperimental(Attribute)}. The {@link #putRecordComponentInfo(ByteVector)} method
+ * writes the attributes in the order defined by this list, i.e. in the reverse order specified by
+ * the user.
+ */
+ private Attribute firstAttribute;
+
+ /**
+ * Constructs a new {@link RecordComponentWriter}.
+ *
+ * @param symbolTable where the constants used in this RecordComponentWriter must be stored.
+ * @param accessFlags the record component access flags, only synthetic and/or deprecated.
+ * @param name the record component name.
+ * @param descriptor the record component descriptor (see {@link Type}).
+ * @param signature the record component signature. May be {@literal null}.
+ */
+ RecordComponentWriter(
+ final SymbolTable symbolTable,
+ final int accessFlags,
+ final String name,
+ final String descriptor,
+ final String signature) {
+ super(/* latest api = */ Opcodes.ASM7);
+ this.symbolTable = symbolTable;
+ this.accessFlags = accessFlags;
+ this.nameIndex = symbolTable.addConstantUtf8(name);
+ this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
+ if (signature != null) {
+ this.signatureIndex = symbolTable.addConstantUtf8(signature);
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Implementation of the FieldVisitor abstract class
+ // -----------------------------------------------------------------------------------------------
+
+ @Override
+ public AnnotationVisitor visitAnnotationExperimental(
+ final String descriptor, final boolean visible) {
+ if (visible) {
+ return lastRuntimeVisibleAnnotation =
+ AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
+ } else {
+ return lastRuntimeInvisibleAnnotation =
+ AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
+ }
+ }
+
+ @Override
+ public AnnotationVisitor visitTypeAnnotationExperimental(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ if (visible) {
+ return lastRuntimeVisibleTypeAnnotation =
+ AnnotationWriter.create(
+ symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
+ } else {
+ return lastRuntimeInvisibleTypeAnnotation =
+ AnnotationWriter.create(
+ symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
+ }
+ }
+
+ @Override
+ public void visitAttributeExperimental(final Attribute attribute) {
+ // Store the attributes in the reverse order of their visit by this method.
+ attribute.nextAttribute = firstAttribute;
+ firstAttribute = attribute;
+ }
+
+ @Override
+ public void visitEndExperimental() {
+ // Nothing to do.
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Utility methods
+ // -----------------------------------------------------------------------------------------------
+
+ /**
+ * Returns the size of the record component JVMS structure generated by this
+ * RecordComponentWriter. Also adds the names of the attributes of this record component in the
+ * constant pool.
+ *
+ * @return the size in bytes of the record_component_info of the Record attribute.
+ */
+ int computeRecordComponentInfoSize() {
+ // name_index, descriptor_index and attributes_count fields use 6 bytes.
+ int size = 6;
+ size +=
+ Attribute.computeAttributesSize(
+ symbolTable, accessFlags & Opcodes.ACC_DEPRECATED, signatureIndex);
+ size +=
+ AnnotationWriter.computeAnnotationsSize(
+ lastRuntimeVisibleAnnotation,
+ lastRuntimeInvisibleAnnotation,
+ lastRuntimeVisibleTypeAnnotation,
+ lastRuntimeInvisibleTypeAnnotation);
+ if (firstAttribute != null) {
+ size += firstAttribute.computeAttributesSize(symbolTable);
+ }
+ return size;
+ }
+
+ /**
+ * Puts the content of the record component generated by this RecordComponentWriter into the given
+ * ByteVector.
+ *
+ * @param output where the record_component_info structure must be put.
+ */
+ void putRecordComponentInfo(final ByteVector output) {
+ output.putShort(nameIndex).putShort(descriptorIndex);
+ // Compute and put the attributes_count field.
+ // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+ int attributesCount = 0;
+ if (signatureIndex != 0) {
+ ++attributesCount;
+ }
+ if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+ ++attributesCount;
+ }
+ if (lastRuntimeVisibleAnnotation != null) {
+ ++attributesCount;
+ }
+ if (lastRuntimeInvisibleAnnotation != null) {
+ ++attributesCount;
+ }
+ if (lastRuntimeVisibleTypeAnnotation != null) {
+ ++attributesCount;
+ }
+ if (lastRuntimeInvisibleTypeAnnotation != null) {
+ ++attributesCount;
+ }
+ if (firstAttribute != null) {
+ attributesCount += firstAttribute.getAttributeCount();
+ }
+ output.putShort(attributesCount);
+ Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
+ AnnotationWriter.putAnnotations(
+ symbolTable,
+ lastRuntimeVisibleAnnotation,
+ lastRuntimeInvisibleAnnotation,
+ lastRuntimeVisibleTypeAnnotation,
+ lastRuntimeInvisibleTypeAnnotation,
+ output);
+ if (firstAttribute != null) {
+ firstAttribute.putAttributes(symbolTable, output);
+ }
+ }
+
+ /**
+ * Collects the attributes of this record component into the given set of attribute prototypes.
+ *
+ * @param attributePrototypes a set of attribute prototypes.
+ */
+ final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
+ attributePrototypes.addAttributes(firstAttribute);
+ }
+}