mirror of
https://github.com/zaaarf/lillero.git
synced 2024-12-22 12:54:54 +01:00
feat: implemented field and method proxies
This commit is contained in:
parent
e8b85872f9
commit
bc649ed0f1
4 changed files with 472 additions and 1 deletions
119
src/main/java/ftbsc/lll/proxies/AbstractProxy.java
Normal file
119
src/main/java/ftbsc/lll/proxies/AbstractProxy.java
Normal file
|
@ -0,0 +1,119 @@
|
|||
package ftbsc.lll.proxies;
|
||||
|
||||
/**
|
||||
* Abstract proxy class, implementing common aspects
|
||||
* of {@link MethodProxy} and {@link FieldProxy}.
|
||||
* @since 0.3.0
|
||||
*/
|
||||
public abstract class AbstractProxy {
|
||||
|
||||
/**
|
||||
* The SRG name of the corresponding class member.
|
||||
*/
|
||||
private final String srgName;
|
||||
|
||||
/**
|
||||
* The fully qualified name (i.e. java.lang.String) of
|
||||
* the parent class.
|
||||
*/
|
||||
private final String parent;
|
||||
|
||||
/**
|
||||
* The modifiers of the member, as a packed int.
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
private final int modifiers;
|
||||
|
||||
/**
|
||||
* @return the SRG name of the item
|
||||
*/
|
||||
public String getSrgName() {
|
||||
return this.srgName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modifiers of the member, as a packed int
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
public int getModifiers() {
|
||||
return this.modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fully qualified name of the parent class
|
||||
*/
|
||||
public String getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the descriptor of the member
|
||||
*/
|
||||
public abstract String getDescriptor();
|
||||
|
||||
/**
|
||||
* The private constructor, should be called by all classes extending this in theirs.
|
||||
* @param srgName the SRG name of the member
|
||||
* @param modifiers the modifiers, as a packed int
|
||||
* @param parent the FQN of the parent class
|
||||
*/
|
||||
protected AbstractProxy(String srgName, int modifiers, String parent) {
|
||||
this.srgName = srgName;
|
||||
this.modifiers = modifiers;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Builder for the generic proxy.
|
||||
* @param <T> the type of proxy
|
||||
*/
|
||||
public abstract static class Builder<T extends AbstractProxy> {
|
||||
|
||||
/**
|
||||
* The SRG name of the member.
|
||||
*/
|
||||
protected final String srgName;
|
||||
|
||||
/**
|
||||
* The modifiers of the member, as a packed int.
|
||||
*/
|
||||
protected int modifiers;
|
||||
|
||||
/**
|
||||
* The fully qualified name of the parent.
|
||||
*/
|
||||
protected String parent;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
* @param srgName the SRG name of the member
|
||||
*/
|
||||
protected Builder(String srgName) {
|
||||
this.srgName = srgName;
|
||||
this.modifiers = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parentFQN the fully qualified name of the parent
|
||||
* @return the current state of the builder
|
||||
*/
|
||||
public Builder<T> setParent(String parentFQN) {
|
||||
this.parent = parentFQN;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newModifier the modifier to add
|
||||
* @return the current state of the builder
|
||||
*/
|
||||
public Builder<T> addModifier(int newModifier) {
|
||||
this.modifiers |= newModifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the built proxy object
|
||||
*/
|
||||
public abstract T build();
|
||||
}
|
||||
}
|
113
src/main/java/ftbsc/lll/proxies/FieldProxy.java
Normal file
113
src/main/java/ftbsc/lll/proxies/FieldProxy.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
package ftbsc.lll.proxies;
|
||||
|
||||
import ftbsc.lll.tools.DescriptorBuilder;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* A container for information about class fields to be used
|
||||
* in ASM patching.
|
||||
* @since 0.3.0
|
||||
*/
|
||||
public class FieldProxy extends AbstractProxy {
|
||||
|
||||
/**
|
||||
* The descriptor of the field's type.
|
||||
*/
|
||||
private final String typeDescriptor;
|
||||
|
||||
/**
|
||||
* A public constructor, builds a proxy from a {@link Field}
|
||||
* obtained from reflection.
|
||||
* @param f the {@link Field} object corresponding to this.
|
||||
*/
|
||||
public FieldProxy(Field f) {
|
||||
super(f.getName(), f.getModifiers(), Type.getInternalName(f.getDeclaringClass()));
|
||||
this.typeDescriptor = Type.getDescriptor(f.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* A protected constructor, called only from the builder.
|
||||
* @param srgName the SRG name of the field
|
||||
* @param modifiers the modifiers of the field
|
||||
* @param parent the FQN of the parent class of the field
|
||||
* @param typeDescriptor the type descriptor of the field
|
||||
*/
|
||||
FieldProxy(String srgName, int modifiers, String parent, String typeDescriptor) {
|
||||
super(srgName, modifiers, parent);
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the field's type descriptor
|
||||
*/
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return typeDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link FieldProxy.Builder}.
|
||||
* @param srgName the SRG name of the field
|
||||
* @return the builder object for field proxies
|
||||
*/
|
||||
public static Builder builder(String srgName) {
|
||||
return new Builder(srgName);
|
||||
}
|
||||
|
||||
public static class Builder extends AbstractProxy.Builder<FieldProxy> {
|
||||
/**
|
||||
* The descriptor of the field's type.
|
||||
*/
|
||||
private String typeDescriptor;
|
||||
|
||||
/**
|
||||
* The constructor of the builder, used only internally.
|
||||
* @param srgName the SRG name of the field
|
||||
*/
|
||||
Builder(String srgName) {
|
||||
super(srgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the descriptor of the field type to the given {@link String}.
|
||||
* @param typeDescriptor the descriptor of the field type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder setDescriptor(String typeDescriptor) {
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the descriptor of the field type to match the give {@link Class}.
|
||||
* @param fqn the fully qualified name of the field type
|
||||
* @param arrayLevel the array level of the field type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder setType(String fqn, int arrayLevel) {
|
||||
this.typeDescriptor = DescriptorBuilder.nameToDescriptor(fqn, arrayLevel);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the descriptor of the field type to match the give {@link Class}.
|
||||
* @param type a {@link Class} object representing the field type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder setType(Class<?> type) {
|
||||
this.typeDescriptor = Type.getDescriptor(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link FieldProxy} of the given kind.
|
||||
* @return the built {@link FieldProxy}
|
||||
*/
|
||||
@Override
|
||||
public FieldProxy build() {
|
||||
return new FieldProxy(this.srgName, this.modifiers, this.parent, this.typeDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
223
src/main/java/ftbsc/lll/proxies/MethodProxy.java
Normal file
223
src/main/java/ftbsc/lll/proxies/MethodProxy.java
Normal file
|
@ -0,0 +1,223 @@
|
|||
package ftbsc.lll.proxies;
|
||||
|
||||
import ftbsc.lll.tools.DescriptorBuilder;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A container for information about class methods to be used
|
||||
* in ASM patching.
|
||||
* @since 0.3.0
|
||||
*/
|
||||
public class MethodProxy extends AbstractProxy {
|
||||
|
||||
/**
|
||||
* The parameters of the method.
|
||||
* It holds fully qualified names for objects, and {@link Class}
|
||||
* objects for primitives.
|
||||
*/
|
||||
private final Object[] parameters;
|
||||
|
||||
/**
|
||||
* The return type of the method.
|
||||
* It contains if it's an object, or a {@link Class}
|
||||
* object for primitives.
|
||||
*/
|
||||
private final Object returnType;
|
||||
|
||||
/**
|
||||
* Caches the the descriptor after generating it once for
|
||||
* performance.
|
||||
*/
|
||||
private String descriptorCache;
|
||||
|
||||
/**
|
||||
* A public constructor, builds a proxy from a {@link Method}
|
||||
* obtained from reflection.
|
||||
* @param m the {@link Method} object corresponding to this.
|
||||
*/
|
||||
public MethodProxy(Method m) {
|
||||
super(m.getName(), m.getModifiers(), Type.getInternalName(m.getDeclaringClass()));
|
||||
List<Object> parameters = new ArrayList<>();
|
||||
for(Class<?> p : m.getParameterTypes())
|
||||
parameters.add(p.isPrimitive() ? p : new TypeContainer(p));
|
||||
this.parameters = parameters.toArray();
|
||||
Class<?> returnType = m.getReturnType();
|
||||
this.returnType = returnType.isPrimitive() ? returnType : new TypeContainer(returnType);
|
||||
}
|
||||
|
||||
/**
|
||||
* A protected constructor, called only from the builder.
|
||||
* @param srgName the SRG name of the method
|
||||
* @param modifiers the modifiers of the method
|
||||
* @param parent the FQN of the parent class of the method
|
||||
* @param parameters the parameters of the method
|
||||
* @param returnType the return type of the method
|
||||
*/
|
||||
protected MethodProxy(String srgName, int modifiers, String parent, Object[] parameters, Object returnType) {
|
||||
super(srgName, modifiers, parent);
|
||||
this.parameters = parameters;
|
||||
this.returnType = returnType;
|
||||
this.descriptorCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds (or returns from cache if present)
|
||||
* the method's descriptor.
|
||||
* @return the method's descriptor
|
||||
*/
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
if(this.descriptorCache != null)
|
||||
return this.descriptorCache;
|
||||
DescriptorBuilder b = new DescriptorBuilder();
|
||||
for(Object p : this.parameters)
|
||||
addParameterToBuilder(b, p);
|
||||
addParameterToBuilder(b, this.returnType);
|
||||
this.descriptorCache = b.build();
|
||||
return this.descriptorCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* A static method used internally to correctly insert a
|
||||
* {@link TypeContainer} into a {@link DescriptorBuilder}.
|
||||
* @param b the {@link DescriptorBuilder}
|
||||
* @param p the {@link TypeContainer}
|
||||
*/
|
||||
private static void addParameterToBuilder(DescriptorBuilder b, Object p) {
|
||||
if(p instanceof TypeContainer) {
|
||||
TypeContainer param = (TypeContainer) p;
|
||||
b.addParameter(param.fqn, param.arrayLevel);
|
||||
} else b.addParameter((Class<?>) p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link MethodProxy.Builder}.
|
||||
* @param srgName the SRG name of the method
|
||||
* @return the builder object for method proxies
|
||||
*/
|
||||
public static Builder builder(String srgName) {
|
||||
return new Builder(srgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder object for {@link MethodProxy}.
|
||||
*/
|
||||
public static class Builder extends AbstractProxy.Builder<MethodProxy> {
|
||||
/**
|
||||
* The parameters of the method.
|
||||
*/
|
||||
private final List<Object> parameters;
|
||||
|
||||
/**
|
||||
* The return type of the method. Defaults to void.
|
||||
*/
|
||||
private Object returnType;
|
||||
|
||||
/**
|
||||
* The constructor of the builder, used only internally.
|
||||
* @param srgName the SRG name of the method
|
||||
*/
|
||||
Builder(String srgName) {
|
||||
super(srgName);
|
||||
this.parameters = new ArrayList<>();
|
||||
this.returnType = void.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter of a given type.
|
||||
* @param fqn the fully qualified name of the parameter type
|
||||
* @param arrayLevel the array level of the parameter type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder addParameter(String fqn, int arrayLevel) {
|
||||
this.parameters.add(new TypeContainer(fqn, arrayLevel));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter of a given type.
|
||||
* @param paramType the {@link Class} object corresponding to
|
||||
* the parameter type.
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder addParameter(Class<?> paramType) {
|
||||
this.parameters.add(paramType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type to the given type.
|
||||
* @param fqn the fully qualified name of the return type
|
||||
* @param arrayLevel the array level of the return type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder setReturnType(String fqn, int arrayLevel) {
|
||||
this.returnType = new TypeContainer(fqn, arrayLevel);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type to the given type.
|
||||
* @param returnType the {@link Class} object corresponding to
|
||||
* the return type
|
||||
* @return the builder's state after the change
|
||||
*/
|
||||
public Builder setReturnType(Class<?> returnType) {
|
||||
this.returnType = returnType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link MethodProxy} of the given kind.
|
||||
* @return the built {@link MethodProxy}
|
||||
*/
|
||||
@Override
|
||||
public MethodProxy build() {
|
||||
return new MethodProxy(srgName, modifiers, parent, parameters.toArray(), returnType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A container class, holding information about a given type.
|
||||
*/
|
||||
protected static class TypeContainer {
|
||||
/**
|
||||
* The fully qualified name of the type.
|
||||
*/
|
||||
public final String fqn;
|
||||
|
||||
/**
|
||||
* The array level of the type.
|
||||
*/
|
||||
public final int arrayLevel;
|
||||
|
||||
/**
|
||||
* Public constructor for the class.
|
||||
* @param fqn the fully qualified name of the type
|
||||
* @param arrayLevel the array level of the type
|
||||
*/
|
||||
public TypeContainer(String fqn, int arrayLevel) {
|
||||
this.fqn = fqn;
|
||||
this.arrayLevel = arrayLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor for the class, extracting the
|
||||
* necessary information from a {@link Class} object.
|
||||
* @param clazz the class object
|
||||
*/
|
||||
public TypeContainer(Class<?> clazz) {
|
||||
int arrayLevel = 0;
|
||||
while(clazz.isArray()) {
|
||||
arrayLevel++;
|
||||
clazz = clazz.getComponentType();
|
||||
}
|
||||
this.arrayLevel = arrayLevel;
|
||||
this.fqn = clazz.getCanonicalName();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package ftbsc.lll.tools;
|
||||
|
||||
import ftbsc.lll.proxies.MethodProxy;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
|
@ -62,7 +63,7 @@ public class StackTools implements Opcodes {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new local variable, lasting in scope between two given LabelNodes.
|
||||
* Creates a new local variable, lasting in scope between two given {@link LabelNode}s.
|
||||
* @param method the method for which to declare the local variable
|
||||
* @param name the variable's name
|
||||
* @param desc the type descriptor for the new variable
|
||||
|
@ -83,4 +84,19 @@ public class StackTools implements Opcodes {
|
|||
method.localVariables.add(variable);
|
||||
return targetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given {@link MethodProxy} with the given opcode.
|
||||
* @param m a {@link MethodProxy} representing the method to call.
|
||||
* @return a {@link MethodInsnNode} representing the build node.
|
||||
* @since 0.3.0
|
||||
*/
|
||||
public static MethodInsnNode call(MethodProxy m, int opcode) {
|
||||
return new MethodInsnNode(
|
||||
opcode,
|
||||
m.getParent().replace('.', '/'),
|
||||
m.getSrgName(),
|
||||
m.getDescriptor()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue