summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs')
-rw-r--r--src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs122
1 files changed, 61 insertions, 61 deletions
diff --git a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
index 5f0ecfa0..b5fc1f57 100644
--- a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
+++ b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
// This temporary utility fixes an esoteric issue in XNA Framework where deserialization depends on
// the order of fields returned by Type.GetFields, but that order changes after Harmony/MonoMod use
// reflection to access the fields due to an issue in .NET Framework.
@@ -7,15 +5,15 @@
//
// This will be removed when Harmony/MonoMod are updated to incorporate the fix.
//
-// Special thanks to 0x0ade for submitting this worokaround! Copy/pasted and adapted from MonoMod.
+// Special thanks to 0x0ade for submitting this workaround! Copy/pasted and adapted from MonoMod.
using System;
-using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using HarmonyLib;
-using System.Reflection.Emit;
// ReSharper disable once CheckNamespace -- Temporary hotfix submitted by the MonoMod author.
namespace MonoMod.Utils
@@ -26,33 +24,33 @@ namespace MonoMod.Utils
{
// .NET Framework can break member ordering if using Module.Resolve* on certain members.
- private static object[] _NoArgs = Array.Empty<object>();
- private static object[] _CacheGetterArgs = { /* MemberListType.All */ 0, /* name apparently always null? */ null };
+ private static readonly object[] _NoArgs = Array.Empty<object>();
+ private static readonly object?[] _CacheGetterArgs = { /* MemberListType.All */ 0, /* name apparently always null? */ null };
- private static Type t_RuntimeModule =
+ private static readonly Type? t_RuntimeModule =
typeof(Module).Assembly
.GetType("System.Reflection.RuntimeModule");
- private static PropertyInfo p_RuntimeModule_RuntimeType =
+ private static readonly PropertyInfo? p_RuntimeModule_RuntimeType =
typeof(Module).Assembly
.GetType("System.Reflection.RuntimeModule")
?.GetProperty("RuntimeType", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- private static Type t_RuntimeType =
+ private static readonly Type? t_RuntimeType =
typeof(Type).Assembly
.GetType("System.RuntimeType");
- private static PropertyInfo p_RuntimeType_Cache =
+ private static readonly PropertyInfo? p_RuntimeType_Cache =
typeof(Type).Assembly
.GetType("System.RuntimeType")
?.GetProperty("Cache", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- private static MethodInfo m_RuntimeTypeCache_GetFieldList =
+ private static readonly MethodInfo? m_RuntimeTypeCache_GetFieldList =
typeof(Type).Assembly
.GetType("System.RuntimeType+RuntimeTypeCache")
?.GetMethod("GetFieldList", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- private static MethodInfo m_RuntimeTypeCache_GetPropertyList =
+ private static readonly MethodInfo? m_RuntimeTypeCache_GetPropertyList =
typeof(Type).Assembly
.GetType("System.RuntimeType+RuntimeTypeCache")
?.GetMethod("GetPropertyList", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
@@ -65,37 +63,37 @@ namespace MonoMod.Utils
harmony.Patch(
original: typeof(Harmony).Assembly
- .GetType("HarmonyLib.MethodBodyReader")
+ .GetType("HarmonyLib.MethodBodyReader", throwOnError: true)!
.GetMethod("ReadOperand", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance),
transpiler: new HarmonyMethod(typeof(MiniMonoModHotfix), nameof(ResolveTokenFix))
);
harmony.Patch(
original: typeof(MonoMod.Utils.ReflectionHelper).Assembly
- .GetType("MonoMod.Utils.DynamicMethodDefinition+<>c__DisplayClass3_0")
+ .GetType("MonoMod.Utils.DynamicMethodDefinition+<>c__DisplayClass3_0", throwOnError: true)!
.GetMethod("<_CopyMethodToDefinition>g__ResolveTokenAs|1", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance),
transpiler: new HarmonyMethod(typeof(MiniMonoModHotfix), nameof(ResolveTokenFix))
);
}
- private static IEnumerable<CodeInstruction> ResolveTokenFix(IEnumerable<CodeInstruction> instrs)
+ private static IEnumerable<CodeInstruction> ResolveTokenFix(IEnumerable<CodeInstruction> instructions)
{
- MethodInfo getdecl = typeof(MiniMonoModHotfix).GetMethod(nameof(GetRealDeclaringType));
- MethodInfo fixup = typeof(MiniMonoModHotfix).GetMethod(nameof(FixReflectionCache));
+ MethodInfo getRealDeclaringType = typeof(MiniMonoModHotfix).GetMethod(nameof(MiniMonoModHotfix.GetRealDeclaringType)) ?? throw new InvalidOperationException($"Can't get required method {nameof(MiniMonoModHotfix)}.{nameof(GetRealDeclaringType)}");
+ MethodInfo fixReflectionCache = typeof(MiniMonoModHotfix).GetMethod(nameof(MiniMonoModHotfix.FixReflectionCache)) ?? throw new InvalidOperationException($"Can't get required method {nameof(MiniMonoModHotfix)}.{nameof(FixReflectionCache)}");
- foreach (CodeInstruction instr in instrs)
+ foreach (CodeInstruction instruction in instructions)
{
- yield return instr;
+ yield return instruction;
- if (instr.operand is MethodInfo called)
+ if (instruction.operand is MethodInfo called)
{
switch (called.Name)
{
case "ResolveType":
// type.FixReflectionCache();
yield return new CodeInstruction(OpCodes.Dup);
- yield return new CodeInstruction(OpCodes.Call, fixup);
+ yield return new CodeInstruction(OpCodes.Call, fixReflectionCache);
break;
case "ResolveMember":
@@ -103,15 +101,15 @@ namespace MonoMod.Utils
case "ResolveField":
// member.GetRealDeclaringType().FixReflectionCache();
yield return new CodeInstruction(OpCodes.Dup);
- yield return new CodeInstruction(OpCodes.Call, getdecl);
- yield return new CodeInstruction(OpCodes.Call, fixup);
+ yield return new CodeInstruction(OpCodes.Call, getRealDeclaringType);
+ yield return new CodeInstruction(OpCodes.Call, fixReflectionCache);
break;
}
}
}
}
- public static Type GetModuleType(this Module module)
+ public static Type? GetModuleType(this Module? module)
{
// Sadly we can't blindly resolve type 0x02000001 as the runtime throws ArgumentException.
@@ -120,22 +118,21 @@ namespace MonoMod.Utils
// .NET
if (p_RuntimeModule_RuntimeType != null)
- return (Type)p_RuntimeModule_RuntimeType.GetValue(module, _NoArgs);
+ return (Type?)p_RuntimeModule_RuntimeType.GetValue(module, _NoArgs);
// The hotfix doesn't apply to Mono anyway, thus that's not copied over.
return null;
}
- public static Type GetRealDeclaringType(this MemberInfo member)
- => member.DeclaringType ?? member.Module.GetModuleType();
+ public static Type? GetRealDeclaringType(this MemberInfo member)
+ {
+ return member.DeclaringType ?? member.Module.GetModuleType();
+ }
- public static void FixReflectionCache(this Type type)
+ public static void FixReflectionCache(this Type? type)
{
- if (t_RuntimeType == null ||
- p_RuntimeType_Cache == null ||
- m_RuntimeTypeCache_GetFieldList == null ||
- m_RuntimeTypeCache_GetPropertyList == null)
+ if (t_RuntimeType == null || p_RuntimeType_Cache == null || m_RuntimeTypeCache_GetFieldList == null || m_RuntimeTypeCache_GetPropertyList == null)
return;
for (; type != null; type = type.DeclaringType)
@@ -145,21 +142,17 @@ namespace MonoMod.Utils
if (!t_RuntimeType.IsInstanceOfType(type))
continue;
- CacheFixEntry entry = _CacheFixed.GetValue(type, rt => {
- CacheFixEntry entryNew = new();
- object cache;
- Array properties, fields;
-
+ CacheFixEntry entry = _CacheFixed.GetValue(type, rt =>
+ {
// All RuntimeTypes MUST have a cache, the getter is non-virtual, it creates on demand and asserts non-null.
- entryNew.Cache = cache = p_RuntimeType_Cache.GetValue(rt, _NoArgs);
- entryNew.Properties = properties = _GetArray(cache, m_RuntimeTypeCache_GetPropertyList);
- entryNew.Fields = fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList);
+ object cache = MiniMonoModHotfix.p_RuntimeType_Cache.GetValue(rt, MiniMonoModHotfix._NoArgs)!;
+ Array properties = MiniMonoModHotfix._GetArray(cache, MiniMonoModHotfix.m_RuntimeTypeCache_GetPropertyList);
+ Array fields = MiniMonoModHotfix._GetArray(cache, MiniMonoModHotfix.m_RuntimeTypeCache_GetFieldList);
_FixReflectionCacheOrder<PropertyInfo>(properties);
_FixReflectionCacheOrder<FieldInfo>(fields);
- entryNew.NeedsVerify = false;
- return entryNew;
+ return new CacheFixEntry(cache, properties, fields, needsVerify: false);
});
if (entry.NeedsVerify && !_Verify(entry, type))
@@ -177,44 +170,43 @@ namespace MonoMod.Utils
private static bool _Verify(CacheFixEntry entry, Type type)
{
- object cache;
- Array properties, fields;
-
// The cache can sometimes be invalidated.
// TODO: Figure out if only the arrays get replaced or if the entire cache object gets replaced!
- if (entry.Cache != (cache = p_RuntimeType_Cache.GetValue(type, _NoArgs)))
+ object cache = p_RuntimeType_Cache!.GetValue(type, _NoArgs)!;
+ if (entry.Cache != cache)
{
entry.Cache = cache;
- entry.Properties = _GetArray(cache, m_RuntimeTypeCache_GetPropertyList);
- entry.Fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList);
+ entry.Properties = _GetArray(cache, m_RuntimeTypeCache_GetPropertyList!);
+ entry.Fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList!);
return false;
}
- else if (entry.Properties != (properties = _GetArray(cache, m_RuntimeTypeCache_GetPropertyList)))
+
+ Array properties = _GetArray(cache, m_RuntimeTypeCache_GetPropertyList!);
+ if (entry.Properties != properties)
{
entry.Properties = properties;
- entry.Fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList);
+ entry.Fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList!);
return false;
-
}
- else if (entry.Fields != (fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList)))
+
+ Array fields = _GetArray(cache, m_RuntimeTypeCache_GetFieldList!);
+ if (entry.Fields != fields)
{
entry.Fields = fields;
return false;
}
- else
- {
- // Cache should still be the same, no re-fix necessary.
- return true;
- }
+
+ // Cache should still be the same, no re-fix necessary.
+ return true;
}
private static Array _GetArray(object cache, MethodInfo getter)
{
// Get and discard once, otherwise we might not be getting the actual backing array.
getter.Invoke(cache, _CacheGetterArgs);
- return (Array)getter.Invoke(cache, _CacheGetterArgs);
+ return (Array)getter.Invoke(cache, _CacheGetterArgs)!;
}
private static void _FixReflectionCacheOrder<T>(Array orig) where T : MemberInfo
@@ -222,7 +214,7 @@ namespace MonoMod.Utils
// Sort using a short-lived list.
List<T> list = new List<T>(orig.Length);
for (int i = 0; i < orig.Length; i++)
- list.Add((T)orig.GetValue(i));
+ list.Add((T)orig.GetValue(i)!);
list.Sort((a, b) => a.MetadataToken - b.MetadataToken);
@@ -232,10 +224,18 @@ namespace MonoMod.Utils
private class CacheFixEntry
{
- public object Cache;
+ public object? Cache;
public Array Properties;
public Array Fields;
public bool NeedsVerify;
+
+ public CacheFixEntry(object? cache, Array properties, Array fields, bool needsVerify)
+ {
+ this.Cache = cache;
+ this.Properties = properties;
+ this.Fields = fields;
+ this.NeedsVerify = needsVerify;
+ }
}
}
}