Remove dynamic lambda methods when inside of SideOnly methods
Clean signatures of ReflectionHelper methods.
This commit is contained in:
parent
6745022d46
commit
8fbf4cf115
|
@ -19,8 +19,10 @@
|
|||
|
||||
package net.minecraftforge.fml.common.asm.transformers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraftforge.fml.relauncher.FMLLaunchHandler;
|
||||
|
@ -28,7 +30,11 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
|||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
|
@ -69,6 +75,8 @@ public class SideTransformer implements IClassTransformer
|
|||
fields.remove();
|
||||
}
|
||||
}
|
||||
|
||||
LambdaGatherer lambdaGatherer = new LambdaGatherer();
|
||||
Iterator<MethodNode> methods = classNode.methods.iterator();
|
||||
while(methods.hasNext())
|
||||
{
|
||||
|
@ -80,6 +88,29 @@ public class SideTransformer implements IClassTransformer
|
|||
System.out.println(String.format("Removing Method: %s.%s%s", classNode.name, method.name, method.desc));
|
||||
}
|
||||
methods.remove();
|
||||
lambdaGatherer.accept(method);
|
||||
}
|
||||
}
|
||||
|
||||
// remove dynamic lambda methods that are inside of removed methods
|
||||
List<Handle> dynamicLambdaHandles = lambdaGatherer.getDynamicLambdaHandles();
|
||||
if (!dynamicLambdaHandles.isEmpty())
|
||||
{
|
||||
methods = classNode.methods.iterator();
|
||||
while (methods.hasNext())
|
||||
{
|
||||
MethodNode method = methods.next();
|
||||
for (Handle dynamicLambdaHandle : dynamicLambdaHandles)
|
||||
{
|
||||
if (method.name.equals(dynamicLambdaHandle.getName()) && method.desc.equals(dynamicLambdaHandle.getDesc()))
|
||||
{
|
||||
if (DEBUG)
|
||||
{
|
||||
System.out.println(String.format("Removing Method: %s.%s%s", classNode.name, method.name, method.desc));
|
||||
}
|
||||
methods.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,4 +151,41 @@ public class SideTransformer implements IClassTransformer
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class LambdaGatherer extends MethodVisitor {
|
||||
private static final Handle META_FACTORY = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory",
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;");
|
||||
private final List<Handle> dynamicLambdaHandles = new ArrayList<Handle>();
|
||||
|
||||
public LambdaGatherer() {
|
||||
super(Opcodes.ASM5);
|
||||
}
|
||||
|
||||
public void accept(MethodNode method) {
|
||||
ListIterator<AbstractInsnNode> insnNodeIterator = method.instructions.iterator();
|
||||
while (insnNodeIterator.hasNext())
|
||||
{
|
||||
AbstractInsnNode insnNode = insnNodeIterator.next();
|
||||
if (insnNode.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN)
|
||||
{
|
||||
insnNode.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)
|
||||
{
|
||||
if (META_FACTORY.equals(bsm))
|
||||
{
|
||||
Handle dynamicLambdaHandle = (Handle) bsmArgs[1];
|
||||
dynamicLambdaHandles.add(dynamicLambdaHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Handle> getDynamicLambdaHandles()
|
||||
{
|
||||
return dynamicLambdaHandles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ public class FMLControlledNamespacedRegistry<I extends IForgeRegistryEntry<I>> e
|
|||
{
|
||||
try
|
||||
{
|
||||
ReflectionHelper.findMethod(BitSet.class, this.availabilityMap, new String[]{"trimToSize"}).invoke(this.availabilityMap);
|
||||
ReflectionHelper.findMethod(BitSet.class, "trimToSize", null).invoke(this.availabilityMap);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
*/
|
||||
package net.minecraftforge.fml.relauncher;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -40,6 +45,11 @@ public class ReflectionHelper
|
|||
//this.methodNames = methodNames;
|
||||
}
|
||||
|
||||
public UnableToFindMethodException(Throwable failed)
|
||||
{
|
||||
super(failed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class UnableToFindClassException extends RuntimeException
|
||||
|
@ -170,10 +180,13 @@ public class ReflectionHelper
|
|||
throw new UnableToFindClassException(classNames, err);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #findMethod(Class, String, String, Class[])}
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E> Method findMethod(Class<? super E> clazz, E instance, String[] methodNames, Class<?>... methodTypes)
|
||||
{
|
||||
Exception failed = null;
|
||||
Throwable failed = null;
|
||||
for (String methodName : methodNames)
|
||||
{
|
||||
try
|
||||
|
@ -187,6 +200,47 @@ public class ReflectionHelper
|
|||
failed = e;
|
||||
}
|
||||
}
|
||||
throw new UnableToFindMethodException(methodNames, failed);
|
||||
throw new UnableToFindMethodException(failed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a method with the specified name and parameters in the given class and makes it accessible.
|
||||
* Note: for performance, store the returned value and avoid calling this repeatedly.
|
||||
* <p>
|
||||
* Throws an exception if the method is not found.
|
||||
*
|
||||
* @param clazz The class to find the method on.
|
||||
* @param methodName The name of the method to find (used in developer environments, i.e. "getWorldTime").
|
||||
* @param methodObfName The obfuscated name of the method to find (used in obfuscated environments, i.e. "func_72820_D").
|
||||
* If the name you are looking for is on a class that is never obfuscated, this should be null.
|
||||
* @param parameterTypes The parameter types of the method to find.
|
||||
* @return The method with the specified name and parameters in the given class.
|
||||
*/
|
||||
@Nonnull
|
||||
public static Method findMethod(@Nonnull Class<?> clazz, @Nonnull String methodName, @Nullable String methodObfName, Class<?>... parameterTypes)
|
||||
{
|
||||
Preconditions.checkNotNull(clazz);
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(methodName), "Method name cannot be empty");
|
||||
|
||||
String nameToFind;
|
||||
if (methodObfName == null || (Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"))
|
||||
{
|
||||
nameToFind = methodName;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameToFind = methodObfName;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Method m = clazz.getDeclaredMethod(nameToFind, parameterTypes);
|
||||
m.setAccessible(true);
|
||||
return m;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnableToFindMethodException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue