io.airlift.bytecode.expression.BytecodeExpressions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bytecode Show documentation
Show all versions of bytecode Show documentation
High-level library for generating JVM bytecode
The newest version!
/*
* 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.FieldDefinition;
import io.airlift.bytecode.MethodDefinition;
import io.airlift.bytecode.OpCode;
import io.airlift.bytecode.ParameterizedType;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.stream.StreamSupport;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.toArray;
import static io.airlift.bytecode.ParameterizedType.type;
import static io.airlift.bytecode.expression.ArithmeticBytecodeExpression.createArithmeticBytecodeExpression;
import static io.airlift.bytecode.instruction.Constant.loadBoolean;
import static io.airlift.bytecode.instruction.Constant.loadClass;
import static io.airlift.bytecode.instruction.Constant.loadDouble;
import static io.airlift.bytecode.instruction.Constant.loadDynamic;
import static io.airlift.bytecode.instruction.Constant.loadFloat;
import static io.airlift.bytecode.instruction.Constant.loadInt;
import static io.airlift.bytecode.instruction.Constant.loadLong;
import static io.airlift.bytecode.instruction.Constant.loadNull;
import static io.airlift.bytecode.instruction.Constant.loadString;
import static java.util.Arrays.stream;
import static java.util.Objects.requireNonNull;
public final class BytecodeExpressions
{
private BytecodeExpressions() {}
//
// Constants
//
public static BytecodeExpression constantTrue()
{
return new ConstantBytecodeExpression(boolean.class, loadBoolean(true));
}
public static BytecodeExpression constantFalse()
{
return new ConstantBytecodeExpression(boolean.class, loadBoolean(false));
}
public static BytecodeExpression constantBoolean(boolean value)
{
return new ConstantBytecodeExpression(boolean.class, loadBoolean(value));
}
public static BytecodeExpression constantClass(Class> value)
{
return new ConstantBytecodeExpression(Class.class, loadClass(value));
}
public static BytecodeExpression constantClass(ParameterizedType value)
{
return new ConstantBytecodeExpression(Class.class, loadClass(value));
}
public static BytecodeExpression constantDouble(double value)
{
return new ConstantBytecodeExpression(double.class, loadDouble(value));
}
public static BytecodeExpression constantFloat(float value)
{
return new ConstantBytecodeExpression(float.class, loadFloat(value));
}
public static BytecodeExpression constantInt(int value)
{
return new ConstantBytecodeExpression(int.class, loadInt(value));
}
public static BytecodeExpression constantLong(long value)
{
return new ConstantBytecodeExpression(long.class, loadLong(value));
}
public static BytecodeExpression constantNumber(Number value)
{
if (value instanceof Byte) {
return constantInt((value).intValue()).cast(byte.class);
}
if (value instanceof Short) {
return constantInt((value).intValue()).cast(short.class);
}
if (value instanceof Integer) {
return constantInt((Integer) value);
}
if (value instanceof Long) {
return constantLong((Long) value);
}
if (value instanceof Float) {
return constantFloat((Float) value);
}
if (value instanceof Double) {
return constantDouble((Double) value);
}
throw new IllegalArgumentException("Unsupported number type: " + value.getClass().getName());
}
public static BytecodeExpression constantNull(Class> type)
{
return new ConstantBytecodeExpression(type, loadNull());
}
public static BytecodeExpression constantNull(ParameterizedType type)
{
return new ConstantBytecodeExpression(type, loadNull());
}
public static BytecodeExpression constantString(String value)
{
return new ConstantBytecodeExpression(String.class, loadString(value));
}
public static BytecodeExpression constantDynamic(
String name,
Class> type,
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs)
{
return constantDynamic(name, type(type), bootstrapMethod, ImmutableList.copyOf(bootstrapArgs));
}
public static BytecodeExpression constantDynamic(
String name,
Class> type,
Method bootstrapMethod,
Object... bootstrapArgs)
{
return constantDynamic(name, type(type), bootstrapMethod, ImmutableList.copyOf(bootstrapArgs));
}
public static BytecodeExpression constantDynamic(
String name,
ParameterizedType type,
Method bootstrapMethod,
Object... bootstrapArgs)
{
return constantDynamic(name, type, bootstrapMethod, ImmutableList.copyOf(bootstrapArgs));
}
public static BytecodeExpression constantDynamic(
String name,
ParameterizedType type,
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs)
{
requireNonNull(name, "name is null");
requireNonNull(type, "type is null");
requireNonNull(bootstrapMethod, "bootstrapMethod is null");
requireNonNull(bootstrapArgs, "bootstrapArgs is null");
return new ConstantBytecodeExpression(
type,
loadDynamic(
name,
type,
bootstrapMethod,
toArray(bootstrapArgs, Object.class)));
}
public static BytecodeExpression defaultValue(ParameterizedType type)
{
if (type.isPrimitive()) {
return defaultValue(type.getPrimitiveType());
}
return constantNull(type);
}
public static BytecodeExpression defaultValue(Class> type)
{
requireNonNull(type, "type is null");
if (type == boolean.class) {
return constantInt(0).cast(boolean.class);
}
if (type == byte.class) {
return constantInt(0).cast(byte.class);
}
if (type == int.class) {
return constantInt(0);
}
if (type == short.class) {
return constantInt(0).cast(short.class);
}
if (type == long.class) {
return constantLong(0L);
}
if (type == float.class) {
return constantFloat(0.0f);
}
if (type == double.class) {
return constantDouble(0.0d);
}
checkArgument(!type.isPrimitive(), "Unsupported type %s", type);
return constantNull(type);
}
//
// Get static field
//
public static BytecodeExpression getStatic(Class> declaringClass, String name)
{
return new GetFieldBytecodeExpression(null, declaringClass, name);
}
public static BytecodeExpression getStatic(Field staticField)
{
return new GetFieldBytecodeExpression(null, staticField);
}
public static BytecodeExpression getStatic(FieldDefinition staticField)
{
return new GetFieldBytecodeExpression(null, staticField);
}
public static BytecodeExpression getStatic(ParameterizedType declaringClass, String name, ParameterizedType type)
{
return new GetFieldBytecodeExpression(null, declaringClass, name, type);
}
//
// Set static field
//
public static BytecodeExpression setStatic(Class> declaringClass, String name, BytecodeExpression value)
{
return new SetFieldBytecodeExpression(null, declaringClass, name, value);
}
public static BytecodeExpression setStatic(Field staticField, BytecodeExpression value)
{
return new SetFieldBytecodeExpression(null, staticField, value);
}
public static BytecodeExpression setStatic(FieldDefinition staticField, BytecodeExpression value)
{
return new SetFieldBytecodeExpression(null, staticField, value);
}
public static BytecodeExpression setStatic(ParameterizedType declaringClass, String name, BytecodeExpression value)
{
return new SetFieldBytecodeExpression(null, declaringClass, name, value);
}
//
// New instance
//
public static BytecodeExpression newInstance(Constructor> constructor, BytecodeExpression... parameters)
{
return newInstance(constructor, ImmutableList.copyOf(parameters));
}
public static BytecodeExpression newInstance(Constructor> constructor, Iterable extends BytecodeExpression> parameters)
{
return newInstance(
type(constructor.getDeclaringClass()),
stream(constructor.getParameterTypes())
.map(ParameterizedType::type)
.collect(toImmutableList()),
parameters);
}
public static BytecodeExpression newInstance(Class> returnType, BytecodeExpression... parameters)
{
return newInstance(type(returnType), ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression newInstance(Class> returnType, Iterable extends BytecodeExpression> parameters)
{
return newInstance(type(returnType), parameters);
}
public static BytecodeExpression newInstance(ParameterizedType returnType, BytecodeExpression... parameters)
{
requireNonNull(parameters, "parameters is null");
return newInstance(returnType, ImmutableList.copyOf(parameters));
}
public static BytecodeExpression newInstance(ParameterizedType returnType, Iterable extends BytecodeExpression> parameters)
{
requireNonNull(parameters, "parameters is null");
return newInstance(
returnType,
StreamSupport.stream(parameters.spliterator(), false).map(BytecodeExpression::getType).collect(toImmutableList()),
parameters);
}
public static BytecodeExpression newInstance(Class> returnType, Iterable extends Class>> parameterTypes, BytecodeExpression... parameters)
{
return newInstance(
type(returnType),
StreamSupport.stream(parameterTypes.spliterator(), false).map(ParameterizedType::type).collect(toImmutableList()),
ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression newInstance(ParameterizedType returnType, Iterable parameterTypes, BytecodeExpression... parameters)
{
return newInstance(returnType, parameterTypes, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression newInstance(
ParameterizedType type,
Iterable parameterTypes,
Iterable extends BytecodeExpression> parameters)
{
return new NewInstanceBytecodeExpression(type, parameterTypes, parameters);
}
//
// Array
//
public static BytecodeExpression newArray(ParameterizedType type, int length)
{
return new NewArrayBytecodeExpression(type, length);
}
public static BytecodeExpression newArray(ParameterizedType type, BytecodeExpression length)
{
return new NewArrayBytecodeExpression(type, length);
}
public static BytecodeExpression newArray(ParameterizedType type, BytecodeExpression... elements)
{
return new NewArrayBytecodeExpression(type, ImmutableList.copyOf(elements));
}
public static BytecodeExpression newArray(ParameterizedType type, Iterable extends BytecodeExpression> elements)
{
return new NewArrayBytecodeExpression(type, ImmutableList.copyOf(elements));
}
public static BytecodeExpression length(BytecodeExpression instance)
{
return new ArrayLengthBytecodeExpression(instance);
}
public static BytecodeExpression get(BytecodeExpression instance, BytecodeExpression index)
{
return new GetElementBytecodeExpression(instance, index);
}
public static BytecodeExpression set(BytecodeExpression instance, BytecodeExpression index, BytecodeExpression value)
{
return new SetArrayElementBytecodeExpression(instance, index, value);
}
//
// Invoke static method
//
public static BytecodeExpression invokeStatic(MethodDefinition method, BytecodeExpression... parameters)
{
return invokeStatic(
method.getDeclaringClass().getType(),
method.getName(),
method.getReturnType(),
method.getParameterTypes(),
ImmutableList.copyOf(parameters));
}
public static BytecodeExpression invokeStatic(Method method, BytecodeExpression... parameters)
{
return invokeStatic(method, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeStatic(Method method, Iterable extends BytecodeExpression> parameters)
{
return invokeStatic(
type(method.getDeclaringClass()),
method.getName(),
type(method.getReturnType()),
stream(method.getParameterTypes())
.map(ParameterizedType::type)
.collect(toImmutableList()),
parameters);
}
public static BytecodeExpression invokeStatic(Class> methodTargetType, String methodName, Class> returnType, BytecodeExpression... parameters)
{
return invokeStatic(methodTargetType, methodName, returnType, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeStatic(
Class> methodTargetType,
String methodName,
Class> returnType,
Iterable extends BytecodeExpression> parameters)
{
return invokeStatic(type(methodTargetType), methodName, type(returnType), parameters);
}
public static BytecodeExpression invokeStatic(
ParameterizedType methodTargetType,
String methodName,
ParameterizedType returnType,
Iterable extends BytecodeExpression> parameters)
{
requireNonNull(methodTargetType, "methodTargetType is null");
requireNonNull(returnType, "returnType is null");
requireNonNull(parameters, "parameters is null");
return invokeStatic(
methodTargetType,
methodName,
returnType,
StreamSupport.stream(parameters.spliterator(), false).map(BytecodeExpression::getType).collect(toImmutableList()),
parameters);
}
public static BytecodeExpression invokeStatic(
Class> methodTargetType,
String methodName,
Class> returnType,
Iterable extends Class>> parameterTypes,
BytecodeExpression... parameters)
{
requireNonNull(methodTargetType, "methodTargetType is null");
requireNonNull(returnType, "returnType is null");
requireNonNull(parameterTypes, "parameterTypes is null");
requireNonNull(parameters, "parameters is null");
return invokeStatic(
type(methodTargetType),
methodName,
type(returnType),
StreamSupport.stream(parameterTypes.spliterator(), false).map(ParameterizedType::type).collect(toImmutableList()),
ImmutableList.copyOf(parameters));
}
public static BytecodeExpression invokeStatic(
ParameterizedType methodTargetType,
String methodName,
ParameterizedType returnType,
Iterable parameterTypes,
BytecodeExpression... parameters)
{
return invokeStatic(methodTargetType, methodName, returnType, parameterTypes, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeStatic(
ParameterizedType methodTargetType,
String methodName,
ParameterizedType returnType,
Iterable parameterTypes,
Iterable extends BytecodeExpression> parameters)
{
return new InvokeBytecodeExpression(
null,
methodTargetType,
methodName,
returnType,
parameterTypes,
parameters);
}
//
// Invoke dynamic
//
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
Class> returnType,
BytecodeExpression... parameters)
{
return invokeDynamic(bootstrapMethod, bootstrapArgs, methodName, returnType, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
Class> returnType,
Iterable extends BytecodeExpression> parameters)
{
requireNonNull(returnType, "returnType is null");
requireNonNull(parameters, "parameters is null");
return invokeDynamic(
bootstrapMethod,
bootstrapArgs,
methodName,
type(returnType),
StreamSupport.stream(parameters.spliterator(), false).map(BytecodeExpression::getType).collect(toImmutableList()),
parameters);
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
ParameterizedType returnType,
BytecodeExpression... parameters)
{
return invokeDynamic(bootstrapMethod, bootstrapArgs, methodName, returnType, ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
ParameterizedType returnType,
Iterable extends BytecodeExpression> parameters)
{
requireNonNull(returnType, "returnType is null");
requireNonNull(parameters, "parameters is null");
return invokeDynamic(
bootstrapMethod,
bootstrapArgs,
methodName,
returnType,
StreamSupport.stream(parameters.spliterator(), false).map(BytecodeExpression::getType).collect(toImmutableList()),
parameters);
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
MethodType methodType,
BytecodeExpression... parameters)
{
requireNonNull(methodType, "methodType is null");
requireNonNull(parameters, "parameters is null");
return invokeDynamic(bootstrapMethod, bootstrapArgs, methodName, methodType, ImmutableList.copyOf(parameters));
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
MethodType methodType,
Iterable extends BytecodeExpression> parameters)
{
return invokeDynamic(
bootstrapMethod,
bootstrapArgs,
methodName,
type(methodType.returnType()),
methodType.parameterList().stream().map(ParameterizedType::type).collect(toImmutableList()),
ImmutableList.copyOf(requireNonNull(parameters, "parameters is null")));
}
public static BytecodeExpression invokeDynamic(
Method bootstrapMethod,
Iterable extends Object> bootstrapArgs,
String methodName,
ParameterizedType returnType,
Iterable parameterTypes,
Iterable extends BytecodeExpression> parameters)
{
return new InvokeDynamicBytecodeExpression(
bootstrapMethod,
bootstrapArgs,
methodName,
returnType,
parameters,
parameterTypes);
}
//
// Arithmetic operations
//
public static BytecodeExpression add(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IADD, left, right);
}
public static BytecodeExpression subtract(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.ISUB, left, right);
}
public static BytecodeExpression multiply(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IMUL, left, right);
}
public static BytecodeExpression divide(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IDIV, left, right);
}
public static BytecodeExpression remainder(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IREM, left, right);
}
public static BytecodeExpression bitwiseAnd(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IAND, left, right);
}
public static BytecodeExpression bitwiseOr(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IOR, left, right);
}
public static BytecodeExpression bitwiseXor(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IXOR, left, right);
}
public static BytecodeExpression shiftLeft(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.ISHL, left, right);
}
public static BytecodeExpression shiftRight(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.ISHR, left, right);
}
public static BytecodeExpression shiftRightUnsigned(BytecodeExpression left, BytecodeExpression right)
{
return createArithmeticBytecodeExpression(OpCode.IUSHR, left, right);
}
public static BytecodeExpression negate(BytecodeExpression value)
{
return new NegateBytecodeExpression(value);
}
//
// Comparison operations
//
public static BytecodeExpression lessThan(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.lessThan(left, right);
}
public static BytecodeExpression greaterThan(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.greaterThan(left, right);
}
public static BytecodeExpression lessThanOrEqual(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.lessThanOrEqual(left, right);
}
public static BytecodeExpression greaterThanOrEqual(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.greaterThanOrEqual(left, right);
}
public static BytecodeExpression equal(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.equal(left, right);
}
public static BytecodeExpression notEqual(BytecodeExpression left, BytecodeExpression right)
{
return ComparisonBytecodeExpression.notEqual(left, right);
}
//
// Null comparison operations
//
public static BytecodeExpression isNull(BytecodeExpression value)
{
return equal(value, constantNull(value.getType()));
}
public static BytecodeExpression isNotNull(BytecodeExpression value)
{
return notEqual(value, constantNull(value.getType()));
}
//
// Logical binary operations
//
public static BytecodeExpression and(BytecodeExpression left, BytecodeExpression right)
{
return new AndBytecodeExpression(left, right);
}
public static BytecodeExpression or(BytecodeExpression left, BytecodeExpression right)
{
return new OrBytecodeExpression(left, right);
}
public static BytecodeExpression not(BytecodeExpression value)
{
return new NotBytecodeExpression(value);
}
//
// Complex expressions
//
public static BytecodeExpression inlineIf(BytecodeExpression condition, BytecodeExpression ifTrue, BytecodeExpression ifFalse)
{
return new InlineIfBytecodeExpression(condition, ifTrue, ifFalse);
}
//
// Print
//
public static BytecodeExpression print(BytecodeExpression variable)
{
BytecodeExpression out = getStatic(System.class, "out");
return out.invoke("println", void.class, variable);
}
}