scala.tools.asm.RecordComponentWriter Maven / Gradle / Ivy
// 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 scala.tools.asm;
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);
}
}