All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.airlift.bytecode.expression.CastBytecodeExpression Maven / Gradle / Ivy
/*
* 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 io.airlift.bytecode.expression;
import com.google.common.collect.ImmutableList;
import io.airlift.bytecode.BytecodeBlock;
import io.airlift.bytecode.BytecodeNode;
import io.airlift.bytecode.MethodGenerationContext;
import io.airlift.bytecode.OpCode;
import io.airlift.bytecode.ParameterizedType;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.primitives.Primitives.wrap;
import static io.airlift.bytecode.ParameterizedType.type;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
class CastBytecodeExpression
extends BytecodeExpression
{
private static final ParameterizedType OBJECT_TYPE = type(Object.class);
private final BytecodeExpression instance;
public CastBytecodeExpression(BytecodeExpression instance, ParameterizedType type)
{
super(type);
this.instance = requireNonNull(instance, "instance is null");
checkArgument(type.getPrimitiveType() != void.class, "Type %s can not be cast to %s", instance.getType(), type);
// Call generateBytecode to run the validation logic. The result is thrown away.
// Duplicating the validation logic here is error-prone and introduces duplicate code.
generateBytecode(instance.getType(), getType());
}
@Override
public BytecodeNode getBytecode(MethodGenerationContext generationContext)
{
return new BytecodeBlock()
.append(instance.getBytecode(generationContext))
.append(generateBytecode(instance.getType(), getType()));
}
private static BytecodeBlock generateBytecode(ParameterizedType sourceType, ParameterizedType targetType)
{
BytecodeBlock block = new BytecodeBlock();
switch (getTypeKind(sourceType)) {
case PRIMITIVE:
switch (getTypeKind(targetType)) {
case PRIMITIVE:
castPrimitiveToPrimitive(block, sourceType.getPrimitiveType(), targetType.getPrimitiveType());
return block;
case BOXED_PRIMITVE:
checkArgument(sourceType.getPrimitiveType() == unwrapPrimitiveType(targetType), "Type %s can not be cast to %s", sourceType, targetType);
return block.invokeStatic(targetType, "valueOf", targetType, sourceType);
case OTHER:
checkArgument(OBJECT_TYPE.equals(targetType), "Type %s can not be cast to %s", sourceType, targetType);
Class> sourceClass = sourceType.getPrimitiveType();
return block
.invokeStatic(wrap(sourceClass), "valueOf", wrap(sourceClass), sourceClass)
.checkCast(targetType);
}
case BOXED_PRIMITVE:
switch (getTypeKind(targetType)) {
case PRIMITIVE:
checkArgument(unwrapPrimitiveType(sourceType) == targetType.getPrimitiveType(), "Type %s can not be cast to %s", sourceType, targetType);
return block.invokeVirtual(sourceType, targetType.getPrimitiveType().getSimpleName() + "Value", targetType);
case BOXED_PRIMITVE:
checkArgument(sourceType.equals(targetType), "Type %s can not be cast to %s", sourceType, targetType);
return block;
case OTHER:
return block.checkCast(targetType);
}
case OTHER:
switch (getTypeKind(targetType)) {
case PRIMITIVE:
checkArgument(OBJECT_TYPE.equals(sourceType), "Type %s can not be cast to %s", sourceType, targetType);
return block
.checkCast(wrap(targetType.getPrimitiveType()))
.invokeVirtual(wrap(targetType.getPrimitiveType()), targetType.getPrimitiveType().getSimpleName() + "Value", targetType.getPrimitiveType());
case BOXED_PRIMITVE:
case OTHER:
return block.checkCast(targetType);
}
}
throw new UnsupportedOperationException("unexpected enum value");
}
private static BytecodeBlock castPrimitiveToPrimitive(BytecodeBlock block, Class> sourceType, Class> targetType)
{
if (sourceType == boolean.class) {
if (targetType == boolean.class) {
return block;
}
}
if (sourceType == byte.class) {
if (targetType == byte.class) {
return block;
}
if (targetType == char.class) {
return block;
}
if (targetType == short.class) {
return block;
}
if (targetType == int.class) {
return block;
}
if (targetType == long.class) {
return block.append(OpCode.I2L);
}
if (targetType == float.class) {
return block.append(OpCode.I2F);
}
if (targetType == double.class) {
return block.append(OpCode.I2D);
}
}
if (sourceType == char.class) {
if (targetType == byte.class) {
return block.append(OpCode.I2B);
}
if (targetType == char.class) {
return block;
}
if (targetType == short.class) {
return block;
}
if (targetType == int.class) {
return block;
}
if (targetType == long.class) {
return block.append(OpCode.I2L);
}
if (targetType == float.class) {
return block.append(OpCode.I2F);
}
if (targetType == double.class) {
return block.append(OpCode.I2D);
}
}
if (sourceType == short.class) {
if (targetType == byte.class) {
return block.append(OpCode.I2B);
}
if (targetType == char.class) {
return block.append(OpCode.I2C);
}
if (targetType == short.class) {
return block;
}
if (targetType == int.class) {
return block;
}
if (targetType == long.class) {
return block.append(OpCode.I2L);
}
if (targetType == float.class) {
return block.append(OpCode.I2F);
}
if (targetType == double.class) {
return block.append(OpCode.I2D);
}
}
if (sourceType == int.class) {
if (targetType == boolean.class) {
return block;
}
if (targetType == byte.class) {
return block.append(OpCode.I2B);
}
if (targetType == char.class) {
return block.append(OpCode.I2C);
}
if (targetType == short.class) {
return block.append(OpCode.I2S);
}
if (targetType == int.class) {
return block;
}
if (targetType == long.class) {
return block.append(OpCode.I2L);
}
if (targetType == float.class) {
return block.append(OpCode.I2F);
}
if (targetType == double.class) {
return block.append(OpCode.I2D);
}
}
if (sourceType == long.class) {
if (targetType == byte.class) {
return block.append(OpCode.L2I).append(OpCode.I2B);
}
if (targetType == char.class) {
return block.append(OpCode.L2I).append(OpCode.I2C);
}
if (targetType == short.class) {
return block.append(OpCode.L2I).append(OpCode.I2S);
}
if (targetType == int.class) {
return block.append(OpCode.L2I);
}
if (targetType == long.class) {
return block;
}
if (targetType == float.class) {
return block.append(OpCode.L2F);
}
if (targetType == double.class) {
return block.append(OpCode.L2D);
}
}
if (sourceType == float.class) {
if (targetType == byte.class) {
return block.append(OpCode.F2I).append(OpCode.I2B);
}
if (targetType == char.class) {
return block.append(OpCode.F2I).append(OpCode.I2C);
}
if (targetType == short.class) {
return block.append(OpCode.F2I).append(OpCode.I2S);
}
if (targetType == int.class) {
return block.append(OpCode.F2I);
}
if (targetType == long.class) {
return block.append(OpCode.F2L);
}
if (targetType == float.class) {
return block;
}
if (targetType == double.class) {
return block.append(OpCode.F2D);
}
}
if (sourceType == double.class) {
if (targetType == byte.class) {
return block.append(OpCode.D2I).append(OpCode.I2B);
}
if (targetType == char.class) {
return block.append(OpCode.D2I).append(OpCode.I2C);
}
if (targetType == short.class) {
return block.append(OpCode.D2I).append(OpCode.I2S);
}
if (targetType == int.class) {
return block.append(OpCode.D2I);
}
if (targetType == long.class) {
return block.append(OpCode.D2L);
}
if (targetType == float.class) {
return block.append(OpCode.D2F);
}
if (targetType == double.class) {
return block;
}
}
throw new IllegalArgumentException(format("Type %s can not be cast to %s", sourceType.getName(), targetType.getName()));
}
private static TypeKind getTypeKind(ParameterizedType type)
{
if (type.isPrimitive()) {
return TypeKind.PRIMITIVE;
}
if (unwrapPrimitiveType(type) != null) {
return TypeKind.BOXED_PRIMITVE;
}
return TypeKind.OTHER;
}
private static Class> unwrapPrimitiveType(ParameterizedType boxedPrimitiveType)
{
switch (boxedPrimitiveType.getJavaClassName()) {
case "java.lang.Boolean":
return boolean.class;
case "java.lang.Byte":
return byte.class;
case "java.lang.Character":
return char.class;
case "java.lang.Short":
return short.class;
case "java.lang.Integer":
return int.class;
case "java.lang.Long":
return long.class;
case "java.lang.Float":
return float.class;
case "java.lang.Double":
return double.class;
default:
return null;
}
}
@Override
protected String formatOneLine()
{
return "((" + getType().getSimpleName() + ") " + instance + ")";
}
@Override
public List getChildNodes()
{
return ImmutableList.of(instance);
}
private enum TypeKind
{
PRIMITIVE, BOXED_PRIMITVE, OTHER
}
}