java.net.bytebuddy.implementation.bytecode.member.MethodVariableAccess Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of securemock Show documentation
Show all versions of securemock Show documentation
Libraries for Elasticsearch
The newest version!
/*
* Copyright 2014 - 2018 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.member;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.List;
/**
* A stack assignment that loads a method variable from a given index of the local variable array.
*/
public enum MethodVariableAccess {
/**
* The accessor handler for a JVM-integer.
*/
INTEGER(Opcodes.ILOAD, Opcodes.ISTORE, StackSize.SINGLE),
/**
* The accessor handler for a {@code long}.
*/
LONG(Opcodes.LLOAD, Opcodes.LSTORE, StackSize.DOUBLE),
/**
* The accessor handler for a {@code float}.
*/
FLOAT(Opcodes.FLOAD, Opcodes.FSTORE, StackSize.SINGLE),
/**
* The accessor handler for a {@code double}.
*/
DOUBLE(Opcodes.DLOAD, Opcodes.DSTORE, StackSize.DOUBLE),
/**
* The accessor handler for a reference type.
*/
REFERENCE(Opcodes.ALOAD, Opcodes.ASTORE, StackSize.SINGLE);
/**
* The opcode for loading this variable type.
*/
private final int loadOpcode;
/**
* The opcode for storing a local variable type.
*/
private final int storeOpcode;
/**
* The size of the local variable on the JVM stack.
*/
private final StackSize size;
/**
* Creates a new method variable access for a given JVM type.
*
* @param loadOpcode The opcode for loading this variable type.
* @param storeOpcode The opcode for storing this variable type.
* @param stackSize The size of the JVM type.
*/
MethodVariableAccess(int loadOpcode, int storeOpcode, StackSize stackSize) {
this.loadOpcode = loadOpcode;
this.size = stackSize;
this.storeOpcode = storeOpcode;
}
/**
* Locates the correct accessor for a variable of a given type.
*
* @param typeDefinition The type of the variable to be loaded.
* @return An accessor for the given type.
*/
public static MethodVariableAccess of(TypeDefinition typeDefinition) {
if (typeDefinition.isPrimitive()) {
if (typeDefinition.represents(long.class)) {
return LONG;
} else if (typeDefinition.represents(double.class)) {
return DOUBLE;
} else if (typeDefinition.represents(float.class)) {
return FLOAT;
} else if (typeDefinition.represents(void.class)) {
throw new IllegalArgumentException("Variable type cannot be void");
} else {
return INTEGER;
}
} else {
return REFERENCE;
}
}
/**
* Loads all arguments of the provided method onto the operand stack.
*
* @param methodDescription The method for which all parameters are to be loaded onto the operand stack.
* @return A stack manipulation that loads all parameters of the provided method onto the operand stack.
*/
public static MethodLoading allArgumentsOf(MethodDescription methodDescription) {
return new MethodLoading(methodDescription, MethodLoading.TypeCastingHandler.NoOp.INSTANCE);
}
/**
* Loads a reference to the {@code this} reference what is only meaningful for a non-static method.
*
* @return A stack manipulation loading the {@code this} reference.
*/
public static StackManipulation loadThis() {
return MethodVariableAccess.REFERENCE.loadFrom(0);
}
/**
* Creates a stack assignment for a reading given offset of the local variable array.
*
* @param offset The offset of the variable where {@code double} and {@code long} types count two slots.
* @return A stack manipulation representing the variable read.
*/
public StackManipulation loadFrom(int offset) {
return new OffsetLoading(offset);
}
/**
* Creates a stack assignment for writing to a given offset of the local variable array.
*
* @param offset The offset of the variable where {@code double} and {@code long} types count two slots.
* @return A stack manipulation representing the variable write.
*/
public StackManipulation storeAt(int offset) {
return new OffsetWriting(offset);
}
/**
* Creates a stack assignment for incrementing the given offset of the local variable array.
*
* @param offset The offset of the variable where {@code double} and {@code long} types count two slots.
* @param value The incremented value.
* @return A stack manipulation representing the variable write.
*/
public StackManipulation increment(int offset, int value) {
if (this != INTEGER) {
throw new IllegalStateException("Cannot increment type: " + this);
}
return new OffsetIncrementing(offset, value);
}
/**
* Loads a parameter's value onto the operand stack.
*
* @param parameterDescription The parameter which to load onto the operand stack.
* @return A stack manipulation loading a parameter onto the operand stack.
*/
public static StackManipulation load(ParameterDescription parameterDescription) {
return of(parameterDescription.getType()).loadFrom(parameterDescription.getOffset());
}
/**
* Stores the top operand stack value at the supplied parameter.
*
* @param parameterDescription The parameter which to store a value for.
* @return A stack manipulation storing the top operand stack value at this parameter.
*/
public static StackManipulation store(ParameterDescription parameterDescription) {
return of(parameterDescription.getType()).storeAt(parameterDescription.getOffset());
}
/**
* Increments the value of the supplied parameter.
*
* @param parameterDescription The parameter which to increment.
* @param value The value to increment with.
* @return A stack manipulation incrementing the supplied parameter.
*/
public static StackManipulation increment(ParameterDescription parameterDescription, int value) {
return of(parameterDescription.getType()).increment(parameterDescription.getOffset(), value);
}
/**
* A stack manipulation that loads all parameters of a given method onto the operand stack.
*/
@HashCodeAndEqualsPlugin.Enhance
public static class MethodLoading implements StackManipulation {
/**
* The method for which all parameters are loaded onto the operand stack.
*/
private final MethodDescription methodDescription;
/**
* A type casting handler which is capable of transforming all method parameters.
*/
private final TypeCastingHandler typeCastingHandler;
/**
* Creates a new method loading stack manipulation.
*
* @param methodDescription The method for which all parameters are loaded onto the operand stack.
* @param typeCastingHandler A type casting handler which is capable of transforming all method parameters.
*/
protected MethodLoading(MethodDescription methodDescription, TypeCastingHandler typeCastingHandler) {
this.methodDescription = methodDescription;
this.typeCastingHandler = typeCastingHandler;
}
/**
* {@inheritDoc}
*/
public boolean isValid() {
return true;
}
/**
* {@inheritDoc}
*/
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
List stackManipulations = new ArrayList();
for (ParameterDescription parameterDescription : methodDescription.getParameters()) {
TypeDescription parameterType = parameterDescription.getType().asErasure();
stackManipulations.add(of(parameterType).loadFrom(parameterDescription.getOffset()));
stackManipulations.add(typeCastingHandler.ofIndex(parameterType, parameterDescription.getIndex()));
}
return new Compound(stackManipulations).apply(methodVisitor, implementationContext);
}
/**
* Prepends a reference to the {@code this} instance to the loaded parameters if the represented method is non-static.
*
* @return A stack manipulation that loads all method parameters onto the operand stack while additionally loading a reference
* to {@code this} if the represented is non-static. Any potential parameter transformation is preserved.
*/
public StackManipulation prependThisReference() {
return methodDescription.isStatic()
? this
: new Compound(MethodVariableAccess.loadThis(), this);
}
/**
* Applies a transformation to all loaded arguments of the method being loaded to be casted to the corresponding parameter of
* the provided method. This way, the parameters can be used for invoking a bridge target method.
*
* @param bridgeTarget The method that is the target of the bridge method for which the parameters are being loaded.
* @return A stack manipulation that loads all parameters casted to the types of the supplied bridge target.
*/
public MethodLoading asBridgeOf(MethodDescription bridgeTarget) {
return new MethodLoading(methodDescription, new TypeCastingHandler.ForBridgeTarget(bridgeTarget));
}
/**
* A type casting handler allows a type transformation of all arguments of a method after loading them onto the operand stack.
*/
protected interface TypeCastingHandler {
/**
* Yields a stack transformation to transform the given argument of the method for which the arguments are loaded onto the operand stack.
*
* @param parameterType The parameter type that is to be transformed.
* @param index The index of the transformed parameter.
* @return A transformation to apply after loading the parameter onto the operand stack.
*/
StackManipulation ofIndex(TypeDescription parameterType, int index);
/**
* A non-operative type casting handler.
*/
enum NoOp implements TypeCastingHandler {
/**
* The singleton instance.
*/
INSTANCE;
/**
* {@inheritDoc}
*/
public StackManipulation ofIndex(TypeDescription parameterType, int index) {
return Trivial.INSTANCE;
}
}
/**
* A type casting handler that casts all parameters of a method to the parameter types of a compatible method
* with covariant parameter types. This allows a convenient implementation of bridge methods.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForBridgeTarget implements TypeCastingHandler {
/**
* The target of the method bridge.
*/
private final MethodDescription bridgeTarget;
/**
* Creates a new type casting handler for a bridge target.
*
* @param bridgeTarget The target of the method bridge.
*/
public ForBridgeTarget(MethodDescription bridgeTarget) {
this.bridgeTarget = bridgeTarget;
}
/**
* {@inheritDoc}
*/
public StackManipulation ofIndex(TypeDescription parameterType, int index) {
TypeDescription targetType = bridgeTarget.getParameters().get(index).getType().asErasure();
return parameterType.equals(targetType)
? Trivial.INSTANCE
: TypeCasting.to(targetType);
}
}
}
}
/**
* A stack manipulation for loading a variable of a method's local variable array onto the operand stack.
*/
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
protected class OffsetLoading implements StackManipulation {
/**
* The offset of the local variable array from which the variable should be loaded.
*/
private final int offset;
/**
* Creates a new argument loading stack manipulation.
*
* @param offset The offset of the local variable array from which the variable should be loaded.
*/
protected OffsetLoading(int offset) {
this.offset = offset;
}
/**
* {@inheritDoc}
*/
public boolean isValid() {
return true;
}
/**
* {@inheritDoc}
*/
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
methodVisitor.visitVarInsn(loadOpcode, offset);
return size.toIncreasingSize();
}
}
/**
* A stack manipulation for storing a variable into a method's local variable array.
*/
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
protected class OffsetWriting implements StackManipulation {
/**
* The offset of the local variable array to which the value should be written.
*/
private final int offset;
/**
* Creates a new argument writing stack manipulation.
*
* @param offset The offset of the local variable array to which the value should be written.
*/
protected OffsetWriting(int offset) {
this.offset = offset;
}
/**
* {@inheritDoc}
*/
public boolean isValid() {
return true;
}
/**
* {@inheritDoc}
*/
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
methodVisitor.visitVarInsn(storeOpcode, offset);
return size.toDecreasingSize();
}
}
/**
* A stack manipulation that increments an integer variable.
*/
@HashCodeAndEqualsPlugin.Enhance
protected static class OffsetIncrementing implements StackManipulation {
/**
* The index of the local variable array from which the variable should be loaded.
*/
private final int offset;
/**
* The value to increment.
*/
private final int value;
/**
* Creates a new argument loading stack manipulation.
*
* @param offset The index of the local variable array from which the variable should be loaded.
* @param value The value to increment.
*/
protected OffsetIncrementing(int offset, int value) {
this.offset = offset;
this.value = value;
}
/**
* {@inheritDoc}
*/
public boolean isValid() {
return true;
}
/**
* {@inheritDoc}
*/
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
methodVisitor.visitIincInsn(offset, value);
return new Size(0, 0);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy