/*
 * Copyright 2014 - 2020 Rafael Winterhalter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bytebuddy.implementation.bytecode.member;

import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.enumeration.EnumerationDescription;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import static net.bytebuddy.matcher.ElementMatchers.named;

An access representation to a given field.
/** * An access representation to a given field. */
public enum FieldAccess {
The representation of field access to a static field.
/** * The representation of field access to a static field. */
STATIC(Opcodes.PUTSTATIC, Opcodes.GETSTATIC, StackSize.ZERO),
The representation of field access to an instance field.
/** * The representation of field access to an instance field. */
INSTANCE(Opcodes.PUTFIELD, Opcodes.GETFIELD, StackSize.SINGLE);
The opcode for setting a field value.
/** * The opcode for setting a field value. */
private final int putterOpcode;
The opcode for getting a field value.
/** * The opcode for getting a field value. */
private final int getterOpcode;
The amount of operand slots this field access operation consumes when it is applied before eventually adding new values onto the operand stack.
/** * The amount of operand slots this field access operation consumes when it is applied before eventually * adding new values onto the operand stack. */
private final int targetSizeChange;
Creates a new field access.
Params:
  • putterOpcode – The opcode for setting a field value.
  • getterOpcode – The opcode for getting a field value.
  • targetSizeChange – The amount of operand slots this field access operation consumes when it is applied before eventually adding new values onto the operand stack.
/** * Creates a new field access. * * @param putterOpcode The opcode for setting a field value. * @param getterOpcode The opcode for getting a field value. * @param targetSizeChange The amount of operand slots this field access operation consumes when it is applied * before eventually adding new values onto the operand stack. */
FieldAccess(int putterOpcode, int getterOpcode, StackSize targetSizeChange) { this.putterOpcode = putterOpcode; this.getterOpcode = getterOpcode; this.targetSizeChange = targetSizeChange.getSize(); }
Creates an accessor to read an enumeration value.
Params:
  • enumerationDescription – The description of the enumeration.
Returns:A stack manipulation for reading the enumeration.
/** * Creates an accessor to read an enumeration value. * * @param enumerationDescription The description of the enumeration. * @return A stack manipulation for reading the enumeration. */
public static StackManipulation forEnumeration(EnumerationDescription enumerationDescription) { FieldList<FieldDescription.InDefinedShape> fieldList = enumerationDescription.getEnumerationType() .getDeclaredFields() .filter(named(enumerationDescription.getValue())); return fieldList.size() != 1 || !fieldList.getOnly().isStatic() || !fieldList.getOnly().isPublic() || !fieldList.getOnly().isEnum() ? StackManipulation.Illegal.INSTANCE : STATIC.new AccessDispatcher(fieldList.getOnly()).read(); }
Creates a field access representation for a given field.
Params:
  • fieldDescription – The field to be accessed.
Returns:A field access definition for the given field.
/** * Creates a field access representation for a given field. * * @param fieldDescription The field to be accessed. * @return A field access definition for the given field. */
public static Defined forField(FieldDescription.InDefinedShape fieldDescription) { return fieldDescription.isStatic() ? STATIC.new AccessDispatcher(fieldDescription) : INSTANCE.new AccessDispatcher(fieldDescription); }
Creates a field access representation for a given field. If the field's return type derives from its declared shape, the value is additionally casted to the generically resolved field.
Params:
  • fieldDescription – The field to be accessed.
Returns:A field access definition for the given field.
/** * Creates a field access representation for a given field. If the field's return type derives from its declared shape, the value * is additionally casted to the generically resolved field. * * @param fieldDescription The field to be accessed. * @return A field access definition for the given field. */
public static Defined forField(FieldDescription fieldDescription) { FieldDescription.InDefinedShape declaredField = fieldDescription.asDefined(); return fieldDescription.getType().asErasure().equals(declaredField.getType().asErasure()) ? forField(declaredField) : OfGenericField.of(fieldDescription, forField(declaredField)); }
Representation of a field access for which a getter and a setter can be created.
/** * Representation of a field access for which a getter and a setter can be created. */
public interface Defined {
Creates a getter representation for a given field.
Returns:A stack manipulation representing the retrieval of a field value.
/** * Creates a getter representation for a given field. * * @return A stack manipulation representing the retrieval of a field value. */
StackManipulation read();
Creates a setter representation for a given field.
Returns:A stack manipulation representing the setting of a field value.
/** * Creates a setter representation for a given field. * * @return A stack manipulation representing the setting of a field value. */
StackManipulation write(); }
A dispatcher for implementing a generic read or write access on a field.
/** * A dispatcher for implementing a generic read or write access on a field. */
@HashCodeAndEqualsPlugin.Enhance protected static class OfGenericField implements Defined {
The resolved generic field type.
/** * The resolved generic field type. */
private final TypeDefinition targetType;
An accessor for the field in its defined shape.
/** * An accessor for the field in its defined shape. */
private final Defined defined;
Creates a new dispatcher for a generic field.
Params:
  • targetType – The resolved generic field type.
  • defined – An accessor for the field in its defined shape.
/** * Creates a new dispatcher for a generic field. * * @param targetType The resolved generic field type. * @param defined An accessor for the field in its defined shape. */
protected OfGenericField(TypeDefinition targetType, Defined defined) { this.targetType = targetType; this.defined = defined; }
Creates a generic access dispatcher for a given field.
Params:
  • fieldDescription – The field that is being accessed.
  • fieldAccess – A field accessor for the field in its defined shape.
Returns:A field access dispatcher for the given field.
/** * Creates a generic access dispatcher for a given field. * * @param fieldDescription The field that is being accessed. * @param fieldAccess A field accessor for the field in its defined shape. * @return A field access dispatcher for the given field. */
protected static Defined of(FieldDescription fieldDescription, Defined fieldAccess) { return new OfGenericField(fieldDescription.getType(), fieldAccess); }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation read() { return new StackManipulation.Compound(defined.read(), TypeCasting.to(targetType)); }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation write() { return defined.write(); } }
A dispatcher for implementing a non-generic read or write access on a field.
/** * A dispatcher for implementing a non-generic read or write access on a field. */
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) protected class AccessDispatcher implements Defined {
A description of the accessed field.
/** * A description of the accessed field. */
private final FieldDescription.InDefinedShape fieldDescription;
Creates a new access dispatcher.
Params:
  • fieldDescription – A description of the accessed field.
/** * Creates a new access dispatcher. * * @param fieldDescription A description of the accessed field. */
protected AccessDispatcher(FieldDescription.InDefinedShape fieldDescription) { this.fieldDescription = fieldDescription; }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation read() { return new FieldGetInstruction(); }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation write() { return new FieldPutInstruction(); }
An abstract base implementation for accessing a field value.
/** * An abstract base implementation for accessing a field value. */
private abstract class AbstractFieldInstruction implements StackManipulation {
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isValid() { return true; }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { methodVisitor.visitFieldInsn(getOpcode(), fieldDescription.getDeclaringType().getInternalName(), fieldDescription.getInternalName(), fieldDescription.getDescriptor()); return resolveSize(fieldDescription.getType().getStackSize()); }
Returns the opcode for implementing the field access.
Returns:The opcode for implementing the field access.
/** * Returns the opcode for implementing the field access. * * @return The opcode for implementing the field access. */
protected abstract int getOpcode();
Resolves the actual size of this field access operation.
Params:
  • fieldSize – The size of the accessed field.
Returns:The size of the field access operation based on the field's size.
/** * Resolves the actual size of this field access operation. * * @param fieldSize The size of the accessed field. * @return The size of the field access operation based on the field's size. */
protected abstract Size resolveSize(StackSize fieldSize); }
A reading field access operation.
/** * A reading field access operation. */
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) protected class FieldGetInstruction extends AbstractFieldInstruction { @Override protected int getOpcode() { return getterOpcode; } @Override protected Size resolveSize(StackSize fieldSize) { int sizeChange = fieldSize.getSize() - targetSizeChange; return new Size(sizeChange, sizeChange); } }
A writing field access operation.
/** * A writing field access operation. */
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) protected class FieldPutInstruction extends AbstractFieldInstruction { @Override protected int getOpcode() { return putterOpcode; } @Override protected Size resolveSize(StackSize fieldSize) { return new Size(-1 * (fieldSize.getSize() + targetSizeChange), 0); } } } }