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.BytecodeBlock 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;
import com.google.common.collect.ImmutableList;
import io.airlift.bytecode.debug.LineNumberNode;
import io.airlift.bytecode.instruction.Constant;
import io.airlift.bytecode.instruction.InvokeInstruction;
import io.airlift.bytecode.instruction.JumpInstruction;
import io.airlift.bytecode.instruction.LabelNode;
import io.airlift.bytecode.instruction.TypeInstruction;
import io.airlift.bytecode.instruction.VariableInstruction;
import org.objectweb.asm.MethodVisitor;
import javax.annotation.concurrent.NotThreadSafe;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static io.airlift.bytecode.Access.STATIC;
import static io.airlift.bytecode.ParameterizedType.type;
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.loadFloat;
import static io.airlift.bytecode.instruction.Constant.loadInt;
import static io.airlift.bytecode.instruction.Constant.loadLong;
import static io.airlift.bytecode.instruction.Constant.loadNumber;
import static io.airlift.bytecode.instruction.FieldInstruction.getFieldInstruction;
import static io.airlift.bytecode.instruction.FieldInstruction.getStaticInstruction;
import static io.airlift.bytecode.instruction.FieldInstruction.putFieldInstruction;
import static io.airlift.bytecode.instruction.FieldInstruction.putStaticInstruction;
import static io.airlift.bytecode.instruction.TypeInstruction.cast;
import static io.airlift.bytecode.instruction.TypeInstruction.instanceOf;
import static io.airlift.bytecode.instruction.VariableInstruction.loadVariable;
import static io.airlift.bytecode.instruction.VariableInstruction.storeVariable;
@SuppressWarnings("UnusedDeclaration")
@NotThreadSafe
public class BytecodeBlock
implements BytecodeNode
{
private final List nodes = new ArrayList<>();
private String description;
private int currentLineNumber = -1;
public String getDescription()
{
return description;
}
public BytecodeBlock setDescription(String description)
{
this.description = description;
return this;
}
@Override
public List getChildNodes()
{
return ImmutableList.copyOf(nodes);
}
public BytecodeBlock append(BytecodeNode node)
{
nodes.add(node);
return this;
}
public BytecodeBlock comment(String comment)
{
nodes.add(new Comment(comment));
return this;
}
public BytecodeBlock comment(String comment, Object... args)
{
nodes.add(new Comment(String.format(comment, args)));
return this;
}
public boolean isEmpty()
{
return nodes.isEmpty();
}
public BytecodeBlock visitLabel(LabelNode label)
{
nodes.add(label);
return this;
}
public BytecodeBlock gotoLabel(LabelNode label)
{
nodes.add(JumpInstruction.jump(label));
return this;
}
public BytecodeBlock ifFalseGoto(LabelNode label)
{
return ifZeroGoto(label);
}
public BytecodeBlock ifTrueGoto(LabelNode label)
{
return ifNotZeroGoto(label);
}
public BytecodeBlock ifZeroGoto(LabelNode label)
{
nodes.add(JumpInstruction.jumpIfEqualZero(label));
return this;
}
public BytecodeBlock ifNotZeroGoto(LabelNode label)
{
nodes.add(JumpInstruction.jumpIfNotEqualZero(label));
return this;
}
public BytecodeBlock ifNullGoto(LabelNode label)
{
nodes.add(JumpInstruction.jumpIfNull(label));
return this;
}
public BytecodeBlock ifNotNullGoto(LabelNode label)
{
nodes.add(JumpInstruction.jumpIfNotNull(label));
return this;
}
public BytecodeBlock intAdd()
{
nodes.add(OpCode.IADD);
return this;
}
public BytecodeBlock longAdd()
{
nodes.add(OpCode.LADD);
return this;
}
public BytecodeBlock longCompare()
{
nodes.add(OpCode.LCMP);
return this;
}
/**
* Compare two doubles. If either is NaN comparison is -1.
*/
public BytecodeBlock doubleCompareNanLess()
{
nodes.add(OpCode.DCMPL);
return this;
}
/**
* Compare two doubles. If either is NaN comparison is 1.
*/
public BytecodeBlock doubleCompareNanGreater()
{
nodes.add(OpCode.DCMPG);
return this;
}
public BytecodeBlock intLeftShift()
{
nodes.add(OpCode.ISHL);
return this;
}
public BytecodeBlock intRightShift()
{
nodes.add(OpCode.ISHR);
return this;
}
public BytecodeBlock longLeftShift()
{
nodes.add(OpCode.LSHL);
return this;
}
public BytecodeBlock longRightShift()
{
nodes.add(OpCode.LSHR);
return this;
}
public BytecodeBlock unsignedIntRightShift()
{
nodes.add(OpCode.IUSHR);
return this;
}
public BytecodeBlock unsignedLongRightShift()
{
nodes.add(OpCode.LUSHR);
return this;
}
public BytecodeBlock intBitAnd()
{
nodes.add(OpCode.IAND);
return this;
}
public BytecodeBlock intBitOr()
{
nodes.add(OpCode.IOR);
return this;
}
public BytecodeBlock intBitXor()
{
nodes.add(OpCode.IXOR);
return this;
}
public BytecodeBlock longBitAnd()
{
nodes.add(OpCode.LAND);
return this;
}
public BytecodeBlock longBitOr()
{
nodes.add(OpCode.LOR);
return this;
}
public BytecodeBlock longBitXor()
{
nodes.add(OpCode.LXOR);
return this;
}
public BytecodeBlock intNegate()
{
nodes.add(OpCode.INEG);
return this;
}
public BytecodeBlock intToLong()
{
nodes.add(OpCode.I2L);
return this;
}
public BytecodeBlock longNegate()
{
nodes.add(OpCode.LNEG);
return this;
}
public BytecodeBlock longToInt()
{
nodes.add(OpCode.L2I);
return this;
}
public BytecodeBlock isInstanceOf(Class> type)
{
nodes.add(instanceOf(type));
return this;
}
public BytecodeBlock isInstanceOf(ParameterizedType type)
{
nodes.add(instanceOf(type));
return this;
}
public BytecodeBlock checkCast(Class> type)
{
nodes.add(cast(type));
return this;
}
public BytecodeBlock checkCast(ParameterizedType type)
{
nodes.add(cast(type));
return this;
}
public BytecodeBlock invokeStatic(Method method)
{
nodes.add(InvokeInstruction.invokeStatic(method));
return this;
}
public BytecodeBlock invokeStatic(MethodDefinition method)
{
nodes.add(InvokeInstruction.invokeStatic(method));
return this;
}
public BytecodeBlock invokeStatic(Class> type, String name, Class> returnType, Class>... parameterTypes)
{
nodes.add(InvokeInstruction.invokeStatic(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeStatic(Class> type, String name, Class> returnType, Iterable> parameterTypes)
{
nodes.add(InvokeInstruction.invokeStatic(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeStatic(ParameterizedType type, String name, ParameterizedType returnType, ParameterizedType... parameterTypes)
{
nodes.add(InvokeInstruction.invokeStatic(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeStatic(ParameterizedType type, String name, ParameterizedType returnType, Iterable parameterTypes)
{
nodes.add(InvokeInstruction.invokeStatic(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeVirtual(Method method)
{
nodes.add(InvokeInstruction.invokeVirtual(method));
return this;
}
public BytecodeBlock invokeVirtual(MethodDefinition method)
{
nodes.add(InvokeInstruction.invokeVirtual(method));
return this;
}
public BytecodeBlock invokeVirtual(Class> type, String name, Class> returnType, Class>... parameterTypes)
{
nodes.add(InvokeInstruction.invokeVirtual(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeVirtual(Class> type, String name, Class> returnType, Iterable> parameterTypes)
{
nodes.add(InvokeInstruction.invokeVirtual(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeVirtual(ParameterizedType type, String name, ParameterizedType returnType, ParameterizedType... parameterTypes)
{
nodes.add(InvokeInstruction.invokeVirtual(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeVirtual(ParameterizedType type, String name, ParameterizedType returnType, Iterable parameterTypes)
{
nodes.add(InvokeInstruction.invokeVirtual(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeInterface(Method method)
{
nodes.add(InvokeInstruction.invokeInterface(method));
return this;
}
public BytecodeBlock invokeInterface(MethodDefinition method)
{
nodes.add(InvokeInstruction.invokeInterface(method));
return this;
}
public BytecodeBlock invokeInterface(Class> type, String name, Class> returnType, Class>... parameterTypes)
{
nodes.add(InvokeInstruction.invokeInterface(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeInterface(Class> type, String name, Class> returnType, Iterable> parameterTypes)
{
nodes.add(InvokeInstruction.invokeInterface(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeInterface(ParameterizedType type, String name, ParameterizedType returnType, ParameterizedType... parameterTypes)
{
nodes.add(InvokeInstruction.invokeInterface(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeInterface(ParameterizedType type, String name, ParameterizedType returnType, Iterable parameterTypes)
{
nodes.add(InvokeInstruction.invokeInterface(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeConstructor(Constructor> constructor)
{
nodes.add(InvokeInstruction.invokeConstructor(constructor));
return this;
}
public BytecodeBlock invokeConstructor(Class> type, Class>... parameterTypes)
{
nodes.add(InvokeInstruction.invokeConstructor(type, parameterTypes));
return this;
}
public BytecodeBlock invokeConstructor(Class> type, Iterable> parameterTypes)
{
nodes.add(InvokeInstruction.invokeConstructor(type, parameterTypes));
return this;
}
public BytecodeBlock invokeConstructor(ParameterizedType type, ParameterizedType... parameterTypes)
{
nodes.add(InvokeInstruction.invokeConstructor(type, parameterTypes));
return this;
}
public BytecodeBlock invokeConstructor(ParameterizedType type, Iterable parameterTypes)
{
nodes.add(InvokeInstruction.invokeConstructor(type, parameterTypes));
return this;
}
public BytecodeBlock invokeSpecial(Method method)
{
nodes.add(InvokeInstruction.invokeSpecial(method));
return this;
}
public BytecodeBlock invokeSpecial(MethodDefinition method)
{
nodes.add(InvokeInstruction.invokeSpecial(method));
return this;
}
public BytecodeBlock invokeSpecial(Class> type, String name, Class> returnType, Class>... parameterTypes)
{
nodes.add(InvokeInstruction.invokeSpecial(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeSpecial(Class> type, String name, Class> returnType, Iterable> parameterTypes)
{
nodes.add(InvokeInstruction.invokeSpecial(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeSpecial(ParameterizedType type, String name, ParameterizedType returnType, ParameterizedType... parameterTypes)
{
nodes.add(InvokeInstruction.invokeSpecial(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeSpecial(ParameterizedType type, String name, ParameterizedType returnType, Iterable parameterTypes)
{
nodes.add(InvokeInstruction.invokeSpecial(type, name, returnType, parameterTypes));
return this;
}
public BytecodeBlock invokeDynamic(String name, MethodType methodType, Method bootstrapMethod, Object... defaultBootstrapArguments)
{
nodes.add(InvokeInstruction.invokeDynamic(name, methodType, bootstrapMethod, defaultBootstrapArguments));
return this;
}
public BytecodeNode invokeDynamic(String name,
ParameterizedType returnType,
Iterable parameterTypes,
Method bootstrapMethod,
List bootstrapArgs)
{
nodes.add(InvokeInstruction.invokeDynamic(name, returnType, parameterTypes, bootstrapMethod, bootstrapArgs));
return this;
}
public BytecodeBlock ret(Class> type)
{
if (type == long.class) {
retLong();
}
else if (type == boolean.class) {
retBoolean();
}
else if (type == int.class || type == byte.class || type == char.class || type == short.class) {
retInt();
}
else if (type == float.class) {
retFloat();
}
else if (type == double.class) {
retDouble();
}
else if (type == void.class) {
ret();
}
else if (!type.isPrimitive()) {
retObject();
}
else {
throw new IllegalArgumentException("Unsupported type: " + type.getName());
}
return this;
}
public BytecodeBlock ret()
{
nodes.add(OpCode.RETURN);
return this;
}
public BytecodeBlock retObject()
{
nodes.add(OpCode.ARETURN);
return this;
}
public BytecodeBlock retFloat()
{
nodes.add(OpCode.FRETURN);
return this;
}
public BytecodeBlock retDouble()
{
nodes.add(OpCode.DRETURN);
return this;
}
public BytecodeBlock retBoolean()
{
nodes.add(OpCode.IRETURN);
return this;
}
public BytecodeBlock retLong()
{
nodes.add(OpCode.LRETURN);
return this;
}
public BytecodeBlock retInt()
{
nodes.add(OpCode.IRETURN);
return this;
}
public BytecodeBlock throwObject()
{
nodes.add(OpCode.ATHROW);
return this;
}
public BytecodeBlock newObject(Class> type)
{
nodes.add(TypeInstruction.newObject(type));
return this;
}
public BytecodeBlock newObject(ParameterizedType type)
{
nodes.add(TypeInstruction.newObject(type));
return this;
}
public BytecodeBlock newArray(Class> type)
{
nodes.add(TypeInstruction.newObjectArray(type));
return this;
}
public BytecodeBlock dup()
{
nodes.add(OpCode.DUP);
return this;
}
public BytecodeBlock dup(Class> type)
{
if (type == long.class || type == double.class) {
nodes.add(OpCode.DUP2);
}
else if (type != void.class) {
nodes.add(OpCode.DUP);
}
return this;
}
public BytecodeBlock pop()
{
nodes.add(OpCode.POP);
return this;
}
public BytecodeBlock pop(Class> type)
{
if (type == long.class || type == double.class) {
nodes.add(OpCode.POP2);
}
else if (type != void.class) {
nodes.add(OpCode.POP);
}
return this;
}
public BytecodeBlock pop(ParameterizedType type)
{
Class> primitiveType = type.getPrimitiveType();
if (primitiveType == long.class || primitiveType == double.class) {
nodes.add(OpCode.POP2);
}
else if (primitiveType != void.class) {
nodes.add(OpCode.POP);
}
return this;
}
public BytecodeBlock swap()
{
nodes.add(OpCode.SWAP);
return this;
}
//
// Fields (non-static)
//
public BytecodeBlock getField(Field field)
{
return getField(field.getDeclaringClass(), field.getName(), field.getType());
}
public BytecodeBlock getField(FieldDefinition field)
{
getField(field.getDeclaringClass().getType(), field.getName(), field.getType());
return this;
}
public BytecodeBlock getField(Class> target, String fieldName, Class> fieldType)
{
getField(type(target), fieldName, type(fieldType));
return this;
}
public BytecodeBlock getField(ParameterizedType target, String fieldName, ParameterizedType fieldType)
{
nodes.add(getFieldInstruction(target, fieldName, fieldType));
return this;
}
public BytecodeBlock putField(Field field)
{
return putField(field.getDeclaringClass(), field.getName(), field.getType());
}
public BytecodeBlock putField(Class> target, String fieldName, Class> fieldType)
{
putField(type(target), fieldName, type(fieldType));
return this;
}
public BytecodeBlock putField(FieldDefinition field)
{
checkArgument(!field.getAccess().contains(STATIC), "Field is static: %s", field);
putField(field.getDeclaringClass().getType(), field.getName(), field.getType());
return this;
}
public BytecodeBlock putField(ParameterizedType target, String fieldName, ParameterizedType fieldType)
{
nodes.add(putFieldInstruction(target, fieldName, fieldType));
return this;
}
//
// Static fields
//
public BytecodeBlock getStaticField(FieldDefinition field)
{
getStaticField(field.getDeclaringClass().getType(), field.getName(), field.getType());
return this;
}
public BytecodeBlock getStaticField(Field field)
{
checkArgument(Modifier.isStatic(field.getModifiers()), "Field is not static: %s", field);
getStaticField(type(field.getDeclaringClass()), field.getName(), type(field.getType()));
return this;
}
public BytecodeBlock getStaticField(Class> target, String fieldName, Class> fieldType)
{
nodes.add(getStaticInstruction(target, fieldName, fieldType));
return this;
}
public BytecodeBlock getStaticField(ParameterizedType target, String fieldName, ParameterizedType fieldType)
{
nodes.add(getStaticInstruction(target, fieldName, fieldType));
return this;
}
public BytecodeBlock getStaticField(ParameterizedType target, FieldDefinition field)
{
nodes.add(getStaticInstruction(target, field.getName(), field.getType()));
return this;
}
public BytecodeBlock putStaticField(FieldDefinition field)
{
putStaticField(field.getDeclaringClass().getType(), field.getName(), field.getType());
return this;
}
public BytecodeBlock putStaticField(ParameterizedType target, FieldDefinition field)
{
checkArgument(field.getAccess().contains(STATIC), "Field is not static: %s", field);
putStaticField(target, field.getName(), field.getType());
return this;
}
public BytecodeBlock putStaticField(ParameterizedType target, String fieldName, ParameterizedType fieldType)
{
nodes.add(putStaticInstruction(target, fieldName, fieldType));
return this;
}
//
// Load constants
//
public BytecodeBlock pushNull()
{
nodes.add(OpCode.ACONST_NULL);
return this;
}
public BytecodeBlock push(Class> type)
{
nodes.add(loadClass(type));
return this;
}
public BytecodeBlock push(ParameterizedType type)
{
nodes.add(loadClass(type));
return this;
}
public BytecodeBlock push(String value)
{
nodes.add(Constant.loadString(value));
return this;
}
public BytecodeBlock push(Number value)
{
nodes.add(loadNumber(value));
return this;
}
public BytecodeBlock push(int value)
{
nodes.add(loadInt(value));
return this;
}
public BytecodeBlock push(boolean value)
{
nodes.add(loadBoolean(value));
return this;
}
public BytecodeBlock pushJavaDefault(Class> type)
{
if (type == void.class) {
return this;
}
if (type == boolean.class || type == byte.class || type == char.class || type == short.class || type == int.class) {
return push(0);
}
if (type == long.class) {
return push(0L);
}
if (type == float.class) {
return push(0.0f);
}
if (type == double.class) {
return push(0.0d);
}
return pushNull();
}
public BytecodeBlock initializeVariable(Variable variable)
{
ParameterizedType type = variable.getType();
if (type.getType().length() == 1) {
switch (type.getType().charAt(0)) {
case 'B':
case 'Z':
case 'S':
case 'C':
case 'I':
nodes.add(loadInt(0));
break;
case 'F':
nodes.add(loadFloat(0));
break;
case 'D':
nodes.add(loadDouble(0));
break;
case 'J':
nodes.add(loadLong(0));
break;
default:
checkArgument(false, "Unknown type '%s'", variable.getType());
}
}
else {
nodes.add(Constant.loadNull());
}
nodes.add(storeVariable(variable));
return this;
}
public BytecodeBlock getVariable(Variable variable)
{
nodes.add(loadVariable(variable));
return this;
}
public BytecodeBlock putVariable(Variable variable)
{
nodes.add(storeVariable(variable));
return this;
}
public BytecodeBlock putVariable(Variable variable, Class> type)
{
nodes.add(loadClass(type));
putVariable(variable);
return this;
}
public BytecodeBlock putVariable(Variable variable, ParameterizedType type)
{
nodes.add(loadClass(type));
putVariable(variable);
return this;
}
public BytecodeBlock putVariable(Variable variable, String value)
{
nodes.add(Constant.loadString(value));
putVariable(variable);
return this;
}
public BytecodeBlock putVariable(Variable variable, Number value)
{
nodes.add(loadNumber(value));
putVariable(variable);
return this;
}
public BytecodeBlock putVariable(Variable variable, int value)
{
nodes.add(loadInt(value));
putVariable(variable);
return this;
}
public BytecodeBlock putVariable(Variable variable, boolean value)
{
nodes.add(loadBoolean(value));
putVariable(variable);
return this;
}
public BytecodeBlock incrementVariable(Variable variable, byte increment)
{
String type = variable.getType().getClassName();
checkArgument(ImmutableList.of("byte", "short", "int").contains(type), "variable must be an byte, short or int, but is %s", type);
nodes.add(VariableInstruction.incrementVariable(variable, increment));
return this;
}
public BytecodeBlock getObjectArrayElement()
{
nodes.add(OpCode.AALOAD);
return this;
}
public BytecodeBlock putObjectArrayElement()
{
nodes.add(OpCode.AASTORE);
return this;
}
public BytecodeBlock getIntArrayElement()
{
nodes.add(OpCode.IALOAD);
return this;
}
public BytecodeBlock putIntArrayElement()
{
nodes.add(OpCode.IASTORE);
return this;
}
public BytecodeBlock visitLineNumber(int currentLineNumber)
{
checkArgument(currentLineNumber >= 0, "currentLineNumber must be positive");
if (this.currentLineNumber != currentLineNumber) {
nodes.add(new LineNumberNode(currentLineNumber));
this.currentLineNumber = currentLineNumber;
}
return this;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
for (BytecodeNode node : nodes) {
node.accept(visitor, generationContext);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBlock(parent, this);
}
}