/*
 * 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.collection;

import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.List;

A CollectionFactory that is capable of creating an array of a given type with any number of given values.
/** * A {@link net.bytebuddy.implementation.bytecode.collection.CollectionFactory} that is capable of * creating an array of a given type with any number of given values. */
@HashCodeAndEqualsPlugin.Enhance public class ArrayFactory implements CollectionFactory {
The component type of the array this array factory is creating.
/** * The component type of the array this array factory is creating. */
private final TypeDescription.Generic componentType;
The array creator delegate that supplies suitable opcodes for the creation of an array and the storage of values inside it.
/** * The array creator delegate that supplies suitable opcodes for the creation of an array and the storage of * values inside it. */
private final ArrayCreator arrayCreator;
The decrease of stack size after each value storage operation.
/** * The decrease of stack size after each value storage operation. */
@HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.IGNORE) private final StackManipulation.Size sizeDecrease;
Creates a new array factory with a given ArrayCreator without inferring the type from the component type. Normally, forType(Generic) should be used.
Params:
  • componentType – The component type of the array factory.
  • arrayCreator – The array creator responsible for providing the correct byte code instructions.
/** * Creates a new array factory with a given * {@link net.bytebuddy.implementation.bytecode.collection.ArrayFactory.ArrayCreator} * without inferring the type from the component type. Normally, * {@link net.bytebuddy.implementation.bytecode.collection.ArrayFactory#forType(net.bytebuddy.description.type.TypeDescription.Generic)} * should be used. * * @param componentType The component type of the array factory. * @param arrayCreator The array creator responsible for providing the correct byte code instructions. */
protected ArrayFactory(TypeDescription.Generic componentType, ArrayCreator arrayCreator) { this.componentType = componentType; this.arrayCreator = arrayCreator; // Size decreases by index and array reference (2) and array element (1, 2) after each element storage. sizeDecrease = StackSize.DOUBLE.toDecreasingSize().aggregate(componentType.getStackSize().toDecreasingSize()); }
Creates a new array factory for a given component type.
Params:
  • componentType – The component type of the array that is to be build.
Returns:A new array factory for the given type.
/** * Creates a new array factory for a given component type. * * @param componentType The component type of the array that is to be build. * @return A new array factory for the given type. */
public static ArrayFactory forType(TypeDescription.Generic componentType) { return new ArrayFactory(componentType, makeArrayCreatorFor(componentType)); }
Creates a suitable array creator for the given component type.
Params:
  • componentType – The component type of the array to be created.
Returns:A suitable array creator.
/** * Creates a suitable array creator for the given component type. * * @param componentType The component type of the array to be created. * @return A suitable array creator. */
private static ArrayCreator makeArrayCreatorFor(TypeDefinition componentType) { if (!componentType.isPrimitive()) { return new ArrayCreator.ForReferenceType(componentType.asErasure()); } else if (componentType.represents(boolean.class)) { return ArrayCreator.ForPrimitiveType.BOOLEAN; } else if (componentType.represents(byte.class)) { return ArrayCreator.ForPrimitiveType.BYTE; } else if (componentType.represents(short.class)) { return ArrayCreator.ForPrimitiveType.SHORT; } else if (componentType.represents(char.class)) { return ArrayCreator.ForPrimitiveType.CHARACTER; } else if (componentType.represents(int.class)) { return ArrayCreator.ForPrimitiveType.INTEGER; } else if (componentType.represents(long.class)) { return ArrayCreator.ForPrimitiveType.LONG; } else if (componentType.represents(float.class)) { return ArrayCreator.ForPrimitiveType.FLOAT; } else if (componentType.represents(double.class)) { return ArrayCreator.ForPrimitiveType.DOUBLE; } else { throw new IllegalArgumentException("Cannot create array of type " + componentType); } }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation withValues(List<? extends StackManipulation> stackManipulations) { return new ArrayStackManipulation(stackManipulations); }
{@inheritDoc}
/** * {@inheritDoc} */
public TypeDescription.Generic getComponentType() { return componentType; }
An array creator is responsible for providing correct byte code instructions for creating an array and for storing values into it.
/** * An array creator is responsible for providing correct byte code instructions for creating an array * and for storing values into it. */
protected interface ArrayCreator extends StackManipulation {
The creation of an array consumes one slot on the operand stack and adds a new value to it. Therefore, the operand stack's size is not altered.
/** * The creation of an array consumes one slot on the operand stack and adds a new value to it. * Therefore, the operand stack's size is not altered. */
StackManipulation.Size ARRAY_CREATION_SIZE_CHANGE = StackSize.ZERO.toDecreasingSize();
The opcode instruction for storing a value of the component type inside an array.
Returns:The correct storage opcode for the represented type.
/** * The opcode instruction for storing a value of the component type inside an array. * * @return The correct storage opcode for the represented type. */
int getStorageOpcode();
An array creator implementation for primitive types.
/** * An array creator implementation for primitive types. */
enum ForPrimitiveType implements ArrayCreator {
An array creator for creating boolean[] arrays.
/** * An array creator for creating {@code boolean[]} arrays. */
BOOLEAN(Opcodes.T_BOOLEAN, Opcodes.BASTORE),
An array creator for creating byte[] arrays.
/** * An array creator for creating {@code byte[]} arrays. */
BYTE(Opcodes.T_BYTE, Opcodes.BASTORE),
An array creator for creating short[] arrays.
/** * An array creator for creating {@code short[]} arrays. */
SHORT(Opcodes.T_SHORT, Opcodes.SASTORE),
An array creator for creating char[] arrays.
/** * An array creator for creating {@code char[]} arrays. */
CHARACTER(Opcodes.T_CHAR, Opcodes.CASTORE),
An array creator for creating int[] arrays.
/** * An array creator for creating {@code int[]} arrays. */
INTEGER(Opcodes.T_INT, Opcodes.IASTORE),
An array creator for creating long[] arrays.
/** * An array creator for creating {@code long[]} arrays. */
LONG(Opcodes.T_LONG, Opcodes.LASTORE),
An array creator for creating float[] arrays.
/** * An array creator for creating {@code float[]} arrays. */
FLOAT(Opcodes.T_FLOAT, Opcodes.FASTORE),
An array creator for creating double[] arrays.
/** * An array creator for creating {@code double[]} arrays. */
DOUBLE(Opcodes.T_DOUBLE, Opcodes.DASTORE);
The opcode for creating an array of this type.
/** * The opcode for creating an array of this type. */
private final int creationOpcode;
The opcode for storing a value in an array of this type.
/** * The opcode for storing a value in an array of this type. */
private final int storageOpcode;
Creates a new primitive array creator.
Params:
  • creationOpcode – The opcode for creating an array of this type.
  • storageOpcode – The opcode for storing a value in an array of this type.
/** * Creates a new primitive array creator. * * @param creationOpcode The opcode for creating an array of this type. * @param storageOpcode The opcode for storing a value in an array of this type. */
ForPrimitiveType(int creationOpcode, int storageOpcode) { this.creationOpcode = creationOpcode; this.storageOpcode = storageOpcode; }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isValid() { return true; }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { methodVisitor.visitIntInsn(Opcodes.NEWARRAY, creationOpcode); return ARRAY_CREATION_SIZE_CHANGE; }
{@inheritDoc}
/** * {@inheritDoc} */
public int getStorageOpcode() { return storageOpcode; } }
An array creator implementation for reference types.
/** * An array creator implementation for reference types. */
@HashCodeAndEqualsPlugin.Enhance class ForReferenceType implements ArrayCreator {
The internal name of this array's non-primitive component type.
/** * The internal name of this array's non-primitive component type. */
private final String internalTypeName;
Creates a new array creator for a reference type.
Params:
  • referenceType – The internal name of this array's non-primitive component type.
/** * Creates a new array creator for a reference type. * * @param referenceType The internal name of this array's non-primitive component type. */
protected ForReferenceType(TypeDescription referenceType) { this.internalTypeName = referenceType.getInternalName(); }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isValid() { return true; }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, internalTypeName); return ARRAY_CREATION_SIZE_CHANGE; }
{@inheritDoc}
/** * {@inheritDoc} */
public int getStorageOpcode() { return Opcodes.AASTORE; } } }
A stack manipulation for creating an array as defined by the enclosing array factory.
/** * A stack manipulation for creating an array as defined by the enclosing array factory. */
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) protected class ArrayStackManipulation implements StackManipulation {
A list of value load instructions that are to be stored inside the created array.
/** * A list of value load instructions that are to be stored inside the created array. */
private final List<? extends StackManipulation> stackManipulations;
Creates a new array loading instruction.
Params:
  • stackManipulations – A list of value load instructions that are to be stored inside the created array.
/** * Creates a new array loading instruction. * * @param stackManipulations A list of value load instructions that are to be stored inside the created array. */
protected ArrayStackManipulation(List<? extends StackManipulation> stackManipulations) { this.stackManipulations = stackManipulations; }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isValid() { for (StackManipulation stackManipulation : stackManipulations) { if (!stackManipulation.isValid()) { return false; } } return arrayCreator.isValid(); }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { Size size = IntegerConstant.forValue(stackManipulations.size()).apply(methodVisitor, implementationContext); // The array's construction does not alter the stack's size. size = size.aggregate(arrayCreator.apply(methodVisitor, implementationContext)); int index = 0; for (StackManipulation stackManipulation : stackManipulations) { methodVisitor.visitInsn(Opcodes.DUP); size = size.aggregate(StackSize.SINGLE.toIncreasingSize()); size = size.aggregate(IntegerConstant.forValue(index++).apply(methodVisitor, implementationContext)); size = size.aggregate(stackManipulation.apply(methodVisitor, implementationContext)); methodVisitor.visitInsn(arrayCreator.getStorageOpcode()); size = size.aggregate(sizeDecrease); } return size; } } }