jdk/src/java.base/share/classes/java/lang/classfile/AttributeMapper.java
2025-01-15 02:04:01 +00:00

249 lines
11 KiB
Java

/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.classfile;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.attribute.UnknownAttribute;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.Utf8Entry;
/**
* Bidirectional mapper between the {@code class} file representation of an
* attribute and its API model. The attribute mapper identifies an attribute
* by its {@linkplain Attribute#attributeName name}, and is used to parse the
* {@code class} file representation into a model, and to write the model
* representation back to a {@code class} file.
* <p>
* {@link Attributes} defines the mappers for predefined attributes in the JVMS
* and certain conventional attributes. For other attributes (JVMS {@jvms
* 4.7.1}), users can define their own {@code AttributeMapper}; classes that
* model those attributes should extend {@link CustomAttribute}. To read those
* attributes, user-defined {@code AttributeMapper}s must be registered to the
* {@link ClassFile.AttributeMapperOption}.
*
* @param <A> the attribute type
* @see Attributes
* @see ClassFile.AttributeMapperOption
* @see java.lang.classfile.attribute
* @since 24
*/
public interface AttributeMapper<A extends Attribute<A>> {
/**
* Indicates the data dependency of the {@code class} file representation
* of an attribute. Whether an attribute can be bulk-copied by its binary
* representation to a new {@code class} file depends on if its data refers
* to other parts of its enclosing {@code class} file.
*
* @apiNote
* This dependency is called "stability" because it indicates the conditions
* for a {@code class} file attribute to be eligible for bulk-copying to
* another {@code class} file.
*
* @see AttributeMapper#stability()
* @since 24
*/
enum AttributeStability {
/**
* The attribute contains only standalone data, and has no reference to
* other parts of its enclosing {@code class} file, besides the name of
* the attribute. Thus, its contents can always be bulk-copied to
* another {@code class} file.
* <p>
* For example, a bit mask is standalone data.
*/
STATELESS,
/**
* In addition to standalone data, the attribute refers to the constant
* pool, including the {@link BootstrapMethodsAttribute BootstrapMethods}
* attribute, of its enclosing {@code class} file. Thus, it can be
* bulk-copied when the destination {@code class} file extends its
* constant pool from that of the original {@code class}. It must be
* expanded to translate constant pool references and rewritten when
* constant pool indices are not compatible.
* <p>
* For example, a {@link Utf8Entry} is a reference to the constant pool.
*
* @see ConstantPoolBuilder#of(ClassModel)
* @see ClassFile.ConstantPoolSharingOption
*/
CP_REFS,
/**
* In addition to standalone data and references to the constant pool,
* the attribute refers to positions into the {@code code} array of a
* {@link CodeAttribute Code} attribute. Thus, it can be bulked-copied
* when the {@code code} array is unchanged, which requires that the
* destination {@code class} file extends its constant pool from that of
* the original {@code class}. It must be expanded to translate {@link
* Label}s or constant pool references and rewritten if the {@code code}
* array is perturbed, including when constant pool indices are not
* compatible.
* <p>
* For example, a bci value, modeled by a {@link Label}, is a reference
* to a position in the {@code code} array.
*/
LABELS,
/**
* The attribute refers to structures not managed by the library (type
* variable lists, etc.). As a result, even when the attribute is
* expanded, those references may not be correctly translated, and the
* rewritten results may be incorrect.
* <p>
* If the attribute is read from a {@code class} file, {@link
* ClassFile.AttributesProcessingOption} determines whether to preserve
* or drop the attribute during transformation.
*
* @see ClassFile.AttributesProcessingOption#DROP_UNSTABLE_ATTRIBUTES
*/
UNSTABLE,
/**
* The attribute is completely unknown. As a result, expanding and
* rewriting is not possible, and any difference between the destination
* {@code class} file and its enclosing {@code class} file may make the
* attribute incorrect.
* <p>
* {@link ClassFile.AttributesProcessingOption} determines whether to
* preserve or drop the attribute during transformation.
*
* @see UnknownAttribute
* @see ClassFile.AttributesProcessingOption#DROP_UNSTABLE_ATTRIBUTES
* @see ClassFile.AttributesProcessingOption#DROP_UNKNOWN_ATTRIBUTES
*/
UNKNOWN
}
/**
* {@return the name of the attribute}
*/
String name();
/**
* Creates an {@link Attribute} instance from a {@code class} file for the
* Class-File API.
* <p>
* This method is called by the Class-File API to support reading of
* attributes. Users should never call this method.
* <p>
* The Class-File API makes these promises about the call to this method:
* <ul>
* <li>The {@link Utf8Entry} for the name of the attribute is accessible
* with {@code cf.readEntry(pos - 6, Utf8Entry.class)}, and is validated;
* <li>The length of the attribute is accessible with {@code cf.readInt(pos
* - 4)}, and is validated to be positive and not beyond the length of the
* {@code class} file;
* <li>The {@link AttributedElement} attribute access functionalities on the
* {@code enclosing} model may not be accessed when this method is called,
* but can be accessed later by the returned attribute when it is accessible
* to users.
* </ul>
* <p>
* The returned {@code Attribute} must fulfill these requirements:
* <ul>
* <li>{@link Attribute#attributeMapper()} returns this mapper;
* <li>{@link Attribute#attributeName()} returns the attribute name in the
* {@code class} file.
* </ul>
*
* @apiNote
* Implementations of this method should perform minimal work to return an
* attribute, as this method is called even if the resulting attribute is
* never used. In particular, the implementation should avoid checking the
* validity of the attribute {@code class} file data or performing actions
* that may throw exceptions.
*
* @param enclosing the structure in which this attribute appears
* @param cf provides access to the {@code class} file to read from
* @param pos the offset into the {@code class} file at which the contents
* of the attribute starts
* @return the read attribute
*/
A readAttribute(AttributedElement enclosing, ClassReader cf, int pos);
/**
* Writes an {@link Attribute} instance to a {@code class} file for the
* Class-File API.
* <p>
* This method is called by the Class-File API to support writing of
* attributes. Users should never call this method.
* <p>
* The Class-File API makes these promises about the call to this method:
* <ul>
* <li>{@link Attribute#attributeMapper() attr.attributeMapper()} returns
* this mapper;
* <li>The {@code buf} may already have data written, that its {@link
* BufWriter#size() size} may not be {@code 0}.
* </ul>
* <p>
* The {@code class} file writing must fulfill these requirements:
* <ul>
* <li>The attribute name {@code u2} and attribute length {@code u4} must
* be written to the {@code buf};
* <li>{@link Attribute#attributeName() attr.attributeName()} is written as
* if with {@code buf.writeIndex(attr.attributeName())};
* <li>The attribute length is the length, in bytes, of attribute contents
* written to the {@code buf}, not including the 6 bytes used by the name
* and the length;
* <li>If any information in the API model of the attribute, {@code attr},
* cannot be represented in the {@code class} file format of the attribute,
* an {@link IllegalArgumentException} is thrown.
* </ul>
*
* @apiNote
* {@link BufWriter#patchInt} can be used to update the attribute length
* after the attribute contents are written to the {@code buf}.
*
* @param buf the {@link BufWriter} to which the attribute should be written
* @param attr the attribute to write
* @throws IllegalArgumentException if some data in the API model of the
* attribute is invalid for the {@code class} file format
*/
void writeAttribute(BufWriter buf, A attr);
/**
* {@return whether this attribute may appear more than once in one
* structure}
* <p>
* If an attribute does not allow multiple instances in one structure,
* can be supplied to a {@link ClassFileBuilder}, and multiple instances of
* the attribute are supplied to the builder, the last supplied attribute
* appears on the built structure.
*
* @implSpec The default implementation returns {@code false}.
*/
default boolean allowMultiple() {
return false;
}
/**
* {@return the data dependency of this attribute on the {@code class} file}
*/
AttributeStability stability();
}