net.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveWideningDelegate Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 - Present 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.assign.primitive;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
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.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
/**
* This delegate is responsible for widening a primitive type to represent a larger primitive type. The
* rules for this widening are equivalent to those in the JLS.
*/
public enum PrimitiveWideningDelegate {
/**
* The widening delegate for {@code boolean} values.
*/
BOOLEAN(StackManipulation.Trivial.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Illegal.INSTANCE, // to integer
StackManipulation.Illegal.INSTANCE, // to long
StackManipulation.Illegal.INSTANCE, // to float
StackManipulation.Illegal.INSTANCE), // to double
/**
* The widening delegate for {@code byte} values.
*/
BYTE(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Trivial.INSTANCE, // to byte
StackManipulation.Trivial.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Trivial.INSTANCE, // to integer
new WideningStackManipulation(Opcodes.I2L, StackSize.SINGLE.toIncreasingSize()), // to long
new WideningStackManipulation(Opcodes.I2F, StackSize.ZERO.toIncreasingSize()), // to float
new WideningStackManipulation(Opcodes.I2L, StackSize.SINGLE.toIncreasingSize())), // to double
/**
* The widening delegate for {@code short} values.
*/
SHORT(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Trivial.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Trivial.INSTANCE, // to integer
new WideningStackManipulation(Opcodes.I2L, StackSize.SINGLE.toIncreasingSize()), // to long
new WideningStackManipulation(Opcodes.I2F, StackSize.ZERO.toIncreasingSize()), // to float
new WideningStackManipulation(Opcodes.I2D, StackSize.SINGLE.toIncreasingSize())), // to double
/**
* The widening delegate for {@code char} values.
*/
CHARACTER(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Trivial.INSTANCE, // to character
StackManipulation.Trivial.INSTANCE, // to integer
new WideningStackManipulation(Opcodes.I2L, StackSize.SINGLE.toIncreasingSize()), // to long
new WideningStackManipulation(Opcodes.I2F, StackSize.ZERO.toIncreasingSize()), // to float
new WideningStackManipulation(Opcodes.I2D, StackSize.SINGLE.toIncreasingSize())), // to double
/**
* The widening delegate for {@code int} values.
*/
INTEGER(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Trivial.INSTANCE, // to integer
new WideningStackManipulation(Opcodes.I2L, StackSize.SINGLE.toIncreasingSize()), // to long
new WideningStackManipulation(Opcodes.I2F, StackSize.ZERO.toIncreasingSize()), // to float
new WideningStackManipulation(Opcodes.I2D, StackSize.SINGLE.toIncreasingSize())), // to double
/**
* The widening delegate for {@code long} values.
*/
LONG(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Illegal.INSTANCE, // to integer
StackManipulation.Trivial.INSTANCE, // to long
new WideningStackManipulation(Opcodes.L2F, StackSize.SINGLE.toDecreasingSize()), // to float
new WideningStackManipulation(Opcodes.L2D, StackSize.ZERO.toIncreasingSize())), // to double
/**
* The widening delegate for {@code float} values.
*/
FLOAT(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Illegal.INSTANCE, // to integer
StackManipulation.Illegal.INSTANCE, // to long
StackManipulation.Trivial.INSTANCE, // to float
new WideningStackManipulation(Opcodes.F2D, StackSize.SINGLE.toIncreasingSize())), // to double
/**
* The widening delegate for {@code double} values.
*/
DOUBLE(StackManipulation.Illegal.INSTANCE, // to boolean
StackManipulation.Illegal.INSTANCE, // to byte
StackManipulation.Illegal.INSTANCE, // to short
StackManipulation.Illegal.INSTANCE, // to character
StackManipulation.Illegal.INSTANCE, // to integer
StackManipulation.Illegal.INSTANCE, // to long
StackManipulation.Illegal.INSTANCE, // to float
StackManipulation.Trivial.INSTANCE); // to double
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code boolean}.
*/
private final StackManipulation toBooleanStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code byte}.
*/
private final StackManipulation toByteStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code short}.
*/
private final StackManipulation toShortStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code char}.
*/
private final StackManipulation toCharacterStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code int}.
*/
private final StackManipulation toIntegerStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code long}.
*/
private final StackManipulation toLongStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code float}.
*/
private final StackManipulation toFloatStackManipulation;
/**
* A stack manipulation that widens the type that is represented by this instance to a {@code double}.
*/
private final StackManipulation toDoubleStackManipulation;
/**
* Creates a new primitive widening delegate.
*
* @param toBooleanStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code boolean}.
* @param toByteStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code byte}.
* @param toShortStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code short}.
* @param toCharacterStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code char}.
* @param toIntegerStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code int}.
* @param toLongStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code long}.
* @param toFloatStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code float}.
* @param toDoubleStackManipulation A stack manipulation that widens the type that is represented by this
* instance to a {@code double}.
*/
PrimitiveWideningDelegate(StackManipulation toBooleanStackManipulation,
StackManipulation toByteStackManipulation,
StackManipulation toShortStackManipulation,
StackManipulation toCharacterStackManipulation,
StackManipulation toIntegerStackManipulation,
StackManipulation toLongStackManipulation,
StackManipulation toFloatStackManipulation,
StackManipulation toDoubleStackManipulation) {
this.toBooleanStackManipulation = toBooleanStackManipulation;
this.toByteStackManipulation = toByteStackManipulation;
this.toShortStackManipulation = toShortStackManipulation;
this.toCharacterStackManipulation = toCharacterStackManipulation;
this.toIntegerStackManipulation = toIntegerStackManipulation;
this.toLongStackManipulation = toLongStackManipulation;
this.toFloatStackManipulation = toFloatStackManipulation;
this.toDoubleStackManipulation = toDoubleStackManipulation;
}
/**
* Locates the delegate that is capable of widening the given type into another type.
*
* @param typeDefinition A non-void primitive type that is to be widened into another type.
* @return A delegate for the given type.
*/
public static PrimitiveWideningDelegate forPrimitive(TypeDefinition typeDefinition) {
if (typeDefinition.represents(boolean.class)) {
return BOOLEAN;
} else if (typeDefinition.represents(byte.class)) {
return BYTE;
} else if (typeDefinition.represents(short.class)) {
return SHORT;
} else if (typeDefinition.represents(char.class)) {
return CHARACTER;
} else if (typeDefinition.represents(int.class)) {
return INTEGER;
} else if (typeDefinition.represents(long.class)) {
return LONG;
} else if (typeDefinition.represents(float.class)) {
return FLOAT;
} else if (typeDefinition.represents(double.class)) {
return DOUBLE;
} else {
throw new IllegalArgumentException("Not a primitive, non-void type: " + typeDefinition);
}
}
/**
* Attempts to widen the represented type into another type.
*
* @param typeDefinition A non-void primitive type that is the expected result of the widening operation.
* @return A widening instruction or an illegal stack manipulation if such widening is not legitimate.
*/
public StackManipulation widenTo(TypeDefinition typeDefinition) {
if (typeDefinition.represents(boolean.class)) {
return toBooleanStackManipulation;
} else if (typeDefinition.represents(byte.class)) {
return toByteStackManipulation;
} else if (typeDefinition.represents(short.class)) {
return toShortStackManipulation;
} else if (typeDefinition.represents(char.class)) {
return toCharacterStackManipulation;
} else if (typeDefinition.represents(int.class)) {
return toIntegerStackManipulation;
} else if (typeDefinition.represents(long.class)) {
return toLongStackManipulation;
} else if (typeDefinition.represents(float.class)) {
return toFloatStackManipulation;
} else if (typeDefinition.represents(double.class)) {
return toDoubleStackManipulation;
} else {
throw new IllegalArgumentException("Not a primitive non-void type: " + typeDefinition);
}
}
/**
* A stack manipulation that widens a primitive type into a more general primitive type.
*/
@HashCodeAndEqualsPlugin.Enhance
protected static class WideningStackManipulation extends StackManipulation.AbstractBase {
/**
* The opcode for executing the conversion.
*/
private final int conversionOpcode;
/**
* The size change of applying the conversion.
*/
private final Size size;
/**
* Creates a new widening stack manipulation.
*
* @param conversionOpcode The opcode for executing the conversion.
* @param size The size change of applying the conversion.
*/
protected WideningStackManipulation(int conversionOpcode, Size size) {
this.conversionOpcode = conversionOpcode;
this.size = size;
}
/**
* {@inheritDoc}
*/
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
methodVisitor.visitInsn(conversionOpcode);
return size;
}
}
}