From 0d1a2f2af343bbd6907a74607ff156eefa6cfcc3 Mon Sep 17 00:00:00 2001 From: tterrag Date: Thu, 17 Jan 2019 13:11:54 -0500 Subject: [PATCH] Add utilities that RuntimeEnumExtender expects to exist --- .../common/asm/RuntimeEnumExtender.java | 4 +- .../net/minecraftforge/fml/UnsafeHacks.java | 39 +++++++++++++++---- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java b/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java index 2e7cc1fe7e..2188ce22bb 100644 --- a/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java +++ b/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java @@ -45,7 +45,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService { private final Type ENUM = Type.getType(Enum.class); private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading. private final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class)); - private final Type ENUM_HELPER = Type.getType("Lnet/minecraftforge/common/util/EnumHelper;"); //Again, not direct reference to prevent class loading. + private final Type UNSAFE_HACKS = Type.getType("Lnet/minecraftforge/fml/UnsafeHacks;"); //Again, not direct reference to prevent class loading. private final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class)); private final String NAME_DESC = Type.getMethodDescriptor(STRING); private final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING); @@ -181,7 +181,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService { ins.putstatic(classType.getInternalName(), values.name, values.desc); //EnumHelper.cleanEnumCache(ThisType.class) ins.visitLdcInsn(classType); - ins.invokestatic(ENUM_HELPER.getInternalName(), "cleanEnumCache", CLEAN_DESC, false); + ins.invokestatic(UNSAFE_HACKS.getInternalName(), "cleanEnumCache", CLEAN_DESC, false); //return ret ins.load(vars, classType); ins.areturn(classType); diff --git a/src/main/java/net/minecraftforge/fml/UnsafeHacks.java b/src/main/java/net/minecraftforge/fml/UnsafeHacks.java index a91411e56c..80ec3a5d8f 100644 --- a/src/main/java/net/minecraftforge/fml/UnsafeHacks.java +++ b/src/main/java/net/minecraftforge/fml/UnsafeHacks.java @@ -19,14 +19,17 @@ package net.minecraftforge.fml; +import java.lang.reflect.Field; +import java.util.Optional; + import sun.misc.Unsafe; -import java.lang.reflect.Field; - +@SuppressWarnings("restriction") public class UnsafeHacks { private static final Unsafe UNSAFE; - static { + static + { try { final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); @@ -40,11 +43,11 @@ public class UnsafeHacks } @SuppressWarnings("unchecked") - public static T newInstance(Class packetClass) + public static T newInstance(Class clazz) { try { - return (T) UNSAFE.allocateInstance(packetClass); + return (T) UNSAFE.allocateInstance(clazz); } catch (InstantiationException e) { @@ -53,15 +56,16 @@ public class UnsafeHacks } @SuppressWarnings("unchecked") - public static T getField(Field field, Object object) { + public static T getField(Field field, Object object) + { final long l = UNSAFE.objectFieldOffset(field); return (T) UNSAFE.getObject(object, l); } - public static void setField(Field data, Object object, Object buffer) + public static void setField(Field data, Object object, Object value) { long offset = UNSAFE.objectFieldOffset(data); - UNSAFE.putObject(object, offset, buffer); + UNSAFE.putObject(object, offset, value); } public static int getIntField(Field f, Object obj) @@ -75,4 +79,23 @@ public class UnsafeHacks long offset = UNSAFE.objectFieldOffset(data); UNSAFE.putInt(object, offset, value); } + + // Make sure we don't crash if any future versions change field names + private static Optional findField(Class clazz, String name) + { + for (Field f : clazz.getDeclaredFields()) + { + if (f.getName().equals(name)) + { + return Optional.of(f); + } + } + return Optional.empty(); + } + + public static void cleanEnumCache(Class> enumClass) throws Exception + { + findField(Class.class, "enumConstantDirectory").ifPresent(f -> setField(f, enumClass, null)); + findField(Class.class, "enumConstants").ifPresent(f -> setField(f, enumClass, null)); + } }