All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.bytebuddy.implementation.bytecode.ByteCodeAppender Maven / Gradle / Ivy

The newest version!
package com.fitbur.bytebuddy.implementation.bytecode;

import com.fitbur.bytebuddy.description.method.MethodDescription;
import com.fitbur.bytebuddy.implementation.Implementation;
import com.fitbur.bytebuddy.jar.asm.MethodVisitor;

import java.util.Arrays;
import java.util.List;

/**
 * An appender that generates the byte code for a given method. This is done by writing the byte code instructions to
 * the given ASM {@link com.fitbur.bytebuddy.jar.asm.MethodVisitor}.
 * 

 

* The {@code ByteCodeAppender} is not allowed to write * annotations to the method or call the {@link com.fitbur.bytebuddy.jar.asm.MethodVisitor#visitCode()}, * {@link com.fitbur.bytebuddy.jar.asm.MethodVisitor#visitMaxs(int, int)} or {@link com.fitbur.bytebuddy.jar.asm.MethodVisitor#visitEnd()} * methods which is both done by the entity delegating the call to the {@code ByteCodeAppender}. This is done in order * to allow for the concatenation of several byte code appenders and therefore a more modular description of method * implementations. */ public interface ByteCodeAppender { /** * Applies this byte code appender to a type creation process. * * @param methodVisitor The method visitor to which the byte code appender writes its code to. * @param implementationContext The implementation context of the current type creation process. * @param instrumentedMethod The method that is the target of the instrumentation. * @return The required size for the applied byte code to run. */ Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod); /** * An immutable description of both the operand stack size and the size of the local variable array that is * required to run the code generated by this {@code ByteCodeAppender}. */ class Size { /** * The size of the operand stack. */ private final int operandStackSize; /** * The size of the local variable array. */ private final int localVariableSize; /** * @param operandStackSize The operand stack size that is required for running given byte code. * @param localVariableSize The local variable array size that is required for running given byte code. */ public Size(int operandStackSize, int localVariableSize) { this.operandStackSize = operandStackSize; this.localVariableSize = localVariableSize; } /** * Returns the required operand stack size. * * @return The required operand stack size. */ public int getOperandStackSize() { return operandStackSize; } /** * Returns the required size of the local variable array. * * @return The required size of the local variable array. */ public int getLocalVariableSize() { return localVariableSize; } /** * Merges two sizes in order to describe the size that is required by both size descriptions. * * @param other The other size description. * @return A size description incorporating both size requirements. */ public Size merge(Size other) { return new Size(Math.max(operandStackSize, other.operandStackSize), Math.max(localVariableSize, other.localVariableSize)); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && localVariableSize == ((Size) other).localVariableSize && operandStackSize == ((Size) other).operandStackSize; } @Override public int hashCode() { return 31 * operandStackSize + localVariableSize; } @Override public String toString() { return "ByteCodeAppender.Size{operandStackSize=" + operandStackSize + ", localVariableSize=" + localVariableSize + '}'; } } /** * A compound appender that combines a given number of other byte code appenders. */ class Compound implements ByteCodeAppender { /** * The byte code appenders that are represented by this compound appender in their application order. */ private final List byteCodeAppenders; /** * Creates a new compound byte code appender. * * @param byteCodeAppender The byte code appenders to combine in their order. */ public Compound(ByteCodeAppender... byteCodeAppender) { this(Arrays.asList(byteCodeAppender)); } /** * Creates a new compound byte code appender. * * @param byteCodeAppenders The byte code appenders to combine in their order. */ public Compound(List byteCodeAppenders) { this.byteCodeAppenders = byteCodeAppenders; } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) { Size size = new Size(0, instrumentedMethod.getStackSize()); for (ByteCodeAppender byteCodeAppender : byteCodeAppenders) { size = size.merge(byteCodeAppender.apply(methodVisitor, implementationContext, instrumentedMethod)); } return size; } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && byteCodeAppenders.equals(((Compound) other).byteCodeAppenders); } @Override public int hashCode() { return byteCodeAppenders.hashCode(); } @Override public String toString() { return "ByteCodeAppender.Compound{byteCodeAppenders=" + byteCodeAppenders + '}'; } } /** * A simple byte code appender that only represents a given array of * {@link StackManipulation}s. */ class Simple implements ByteCodeAppender { /** * A compound stack manipulation to be applied for this byte code appender. */ private final StackManipulation stackManipulation; /** * Creates a new simple byte code appender which represents the given stack manipulation. * * @param stackManipulation The stack manipulations to apply for this byte code appender in their application * order. */ public Simple(StackManipulation... stackManipulation) { this.stackManipulation = new StackManipulation.Compound(stackManipulation); } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) { return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize()); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && stackManipulation.equals(((Simple) other).stackManipulation); } @Override public int hashCode() { return stackManipulation.hashCode(); } @Override public String toString() { return "ByteCodeAppender.Simple{stackManipulation=" + stackManipulation + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy