diff --git a/docs/README.ILHelpers.md b/docs/README.ILHelpers.md index b2033350..cf52b15a 100644 --- a/docs/README.ILHelpers.md +++ b/docs/README.ILHelpers.md @@ -1,13 +1 @@ -# `MonoMod.ILHelpers` - -`MonoMod.ILHelpers` is a collection of helpers manually implemented in IL. - -Notably, this contains a backport of `System.Runtime.CompilerServices.Unsafe`, as it exists in .NET 6, to all older -runtimes. This means that any environment which *also* provides that class which is older than .NET 6 will require -an `extern alias` to be able to use properly. - -## Notable APIs - -- `System.Runtime.CompilerServices.Unsafe` -- `MonoMod.ILHelpers` -- \ No newline at end of file +# DO NOT REFERENCE THIS PACKAGE DIRECTLY! Reference MonoMod.Backports instead. \ No newline at end of file diff --git a/docs/RuntimeIssueNotes.md b/docs/RuntimeIssueNotes.md index 435e9bba..0bdbb3f2 100644 --- a/docs/RuntimeIssueNotes.md +++ b/docs/RuntimeIssueNotes.md @@ -1,12 +1,41 @@ # Notes on issues in various runtime versions +Martin, this is wrong. + +## `sizeof` IL opcode does not work with generic parameters on old Mono + +The title says it all. `sizeof` works fine with all other type-specs, but with generic parameters specifically, +it always returns the system pointer size. + +The relevant code is in `metadata/metadata.c`, in `mono_type_size` (which `sizeof` correctly embeds as a constant): + +```c +int +mono_type_size (MonoType *t, int *align) +{ + // ... + + switch (t->type){ + // ... + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: + /* FIXME: Martin, this is wrong. */ + *align = __alignof__(gpointer); + return sizeof (gpointer); + // ... + } + + // ... +} +``` + ## `fixed` on strings in old Mono Some old versions of Mono have broken `conv.u` instruction handling. The following code will crash those old versions with an assert in the JIT's local propagation routine: -```cs +```csharp fixed (char* pStr = "some string") { // ... @@ -15,7 +44,7 @@ fixed (char* pStr = "some string") This is because the sequence that Roslyn emits for `fixed` over a string is this: -``` +```il .locals ( string pinned stringLocalMarkedPinned, char* ptrLocal diff --git a/global.json b/global.json index a2065e21..980041e3 100644 --- a/global.json +++ b/global.json @@ -1,8 +1,8 @@ { "sdk": { "allowPrerelease": true, - "rollForward": "latestMinor", - "version": "8.0.203" + "rollForward": "latestPatch", + "version": "8.0.301" }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.7.56", diff --git a/src/Common/UnsafeAlias.cs b/src/Common/UnsafeAlias.cs index 7d283c3c..29216bec 100644 --- a/src/Common/UnsafeAlias.cs +++ b/src/Common/UnsafeAlias.cs @@ -4,8 +4,8 @@ global using ilhelpers::MonoMod; -#if !NET6_0_OR_GREATER -// Any time we want to use Unsafe, we want ours, not the BCL's +#if !NET6_0_OR_GREATER && (NETSTANDARD2_1_OR_GREATER || NETCOREAPP || NET) +// Any time we want to use Unsafe, we want ours, not the BCL's. Note that we need these funky defs because the location of Unsafe moves between versions. // I would actually rather move the BCL assembly defining it into an alias, but that doesn't seem to be particularly viable global using Unsafe = ilhelpers::System.Runtime.CompilerServices.Unsafe; #else diff --git a/src/MonoMod.Backports/Directory.Build.targets b/src/MonoMod.Backports/Directory.Build.targets index 668c6160..c9b9a8cf 100644 --- a/src/MonoMod.Backports/Directory.Build.targets +++ b/src/MonoMod.Backports/Directory.Build.targets @@ -2,7 +2,7 @@ - + true diff --git a/src/MonoMod.Backports/MonoMod.Backports.csproj b/src/MonoMod.Backports/MonoMod.Backports.csproj index 12048f68..2de1a934 100644 --- a/src/MonoMod.Backports/MonoMod.Backports.csproj +++ b/src/MonoMod.Backports/MonoMod.Backports.csproj @@ -1,11 +1,13 @@  - $(TargetFrameworks);netstandard2.1;netcoreapp2.1;netcoreapp3.0;netcoreapp3.1 + + $(BackportsTargetFrameworks) false - true + false + false false false @@ -27,6 +29,13 @@ or ('$(MMTFKind)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals('$(MMTFVersion)','2.1')))">true + + + + ilhelpers + + + diff --git a/src/MonoMod.Backports/MonoMod.Backports/SRCS.Unsafe.cs b/src/MonoMod.Backports/MonoMod.Backports/SRCS.Unsafe.cs new file mode 100644 index 00000000..44cb4915 --- /dev/null +++ b/src/MonoMod.Backports/MonoMod.Backports/SRCS.Unsafe.cs @@ -0,0 +1,192 @@ +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP || NET +#define UNSAFE_IN_ILHELPERS +#endif + +extern alias ilhelpers; + +// Sometimes these global usings are unused. That's fine. +#pragma warning disable IDE0005 + +// Global usings +global using ilhelpers::MonoMod; + +#if UNSAFE_IN_ILHELPERS && !NET6_0_OR_GREATER +global using Unsafe = ilhelpers::System.Runtime.CompilerServices.Unsafe; +#else +global using Unsafe = System.Runtime.CompilerServices.Unsafe; +#endif + +#pragma warning restore IDE0005 + +#if UNSAFE_IN_ILHELPERS +// SRCS.Unsafe is defined in ILHelpers, so we want to define UnsafeRaw + a type-forwarder + +#if NET6_0_OR_GREATER +using ILImpl = System.Runtime.CompilerServices.Unsafe; +#else +using ILImpl = ilhelpers::System.Runtime.CompilerServices.Unsafe; +#endif + +using System; +using System.Runtime.CompilerServices; + +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(ILImpl))] + +namespace MonoMod.Backports.ILHelpers; + +[CLSCompliant(false)] +public static unsafe class UnsafeRaw +#else +// SRCS.Unsafe is defined here, so we want to define Unsafe + +using MonoMod.Backports; + +using ILImpl = ilhelpers::MonoMod.Backports.ILHelpers.UnsafeRaw; + +namespace System.Runtime.CompilerServices; + +[CLSCompliant(false)] +public static unsafe class Unsafe +#endif +{ + #region Direct forwarders +#nullable disable + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static T Read(void* source) => ILImpl.Read(source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static T ReadUnaligned(void* source) => ILImpl.ReadUnaligned(source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static T ReadUnaligned(ref byte source) => ILImpl.ReadUnaligned(ref source); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void Write(void* destination, T value) => ILImpl.Write(destination, value); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void WriteUnaligned(void* destination, T value) => ILImpl.WriteUnaligned(destination, value); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void WriteUnaligned(ref byte destination, T value) => ILImpl.WriteUnaligned(ref destination, value); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void Copy(void* destination, ref T source) => ILImpl.Copy(destination, ref source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void Copy(ref T destination, void* source) => ILImpl.Copy(ref destination, source); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void* AsPointer(ref T value) => ILImpl.AsPointer(ref value); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void SkipInit(out T value) => ILImpl.SkipInit(out value); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void CopyBlock(void* destination, void* source, uint byteCount) => ILImpl.CopyBlock(destination, source, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void CopyBlock(ref byte destination, ref byte source, uint byteCount) => ILImpl.CopyBlock(ref destination, ref source, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void CopyBlockUnaligned(void* destination, void* source, uint byteCount) => ILImpl.CopyBlockUnaligned(destination, source, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount) => ILImpl.CopyBlockUnaligned(ref destination, ref source, byteCount); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void InitBlock(void* startAddress, byte value, uint byteCount) => ILImpl.InitBlock(startAddress, value, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void InitBlock(ref byte startAddress, byte value, uint byteCount) => ILImpl.InitBlock(ref startAddress, value, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void InitBlockUnaligned(void* startAddress, byte value, uint byteCount) => ILImpl.InitBlockUnaligned(startAddress, value, byteCount); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount) => ILImpl.InitBlockUnaligned(ref startAddress, value, byteCount); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static T As(object o) where T : class => ILImpl.As(o); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T AsRef(void* source) => ref ILImpl.AsRef(source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T AsRef(in T source) => ref ILImpl.AsRef(in source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref TTo As(ref TFrom source) => ref ILImpl.As(ref source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Unbox(object box) where T : struct => ref ILImpl.Unbox(box); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T AddByteOffset(ref T source, nint byteOffset) => ref ILImpl.AddByteOffset(ref source, byteOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T AddByteOffset(ref T source, nuint byteOffset) => ref ILImpl.AddByteOffset(ref source, byteOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T SubtractByteOffset(ref T source, nint byteOffset) => ref ILImpl.SubtractByteOffset(ref source, byteOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T SubtractByteOffset(ref T source, nuint byteOffset) => ref ILImpl.SubtractByteOffset(ref source, byteOffset); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static nint ByteOffset(ref T origin, ref T target) => ILImpl.ByteOffset(ref origin, ref target); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static bool AreSame(ref T left, ref T right) => ILImpl.AreSame(ref left, ref right); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static bool IsAddressGreaterThan(ref T left, ref T right) => ILImpl.IsAddressGreaterThan(ref left, ref right); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static bool IsAddressLessThan(ref T left, ref T right) => ILImpl.IsAddressLessThan(ref left, ref right); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static bool IsNullRef(ref T source) => ILImpl.IsNullRef(ref source); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T NullRef() => ref ILImpl.NullRef(); +#nullable enable + #endregion + +#if !UNSAFE_IN_ILHELPERS + // See docs/RuntimeIssueNotes.md. Until 2015, Mono returned incorrect values for the sizeof opcode when applied to a type parameter. + // To deal with this, we need to compute type size in another way, and return it as appropriate, specializing all of the below accordingly. + private static class PerTypeValues + { + public static readonly nint TypeSize = ComputeTypeSize(); + + private static nint ComputeTypeSize() + { + var array = new T[2]; + return ILImpl.ByteOffset(ref array[0], ref array[1]); + } + } + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static int SizeOf() => (int)PerTypeValues.TypeSize; + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, int elementOffset) => ref ILImpl.AddByteOffset(ref source, (nint)elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void* Add(void* source, int elementOffset) => (byte*)source + (elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, nint elementOffset) => ref ILImpl.AddByteOffset(ref source, elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, nuint elementOffset) => ref ILImpl.AddByteOffset(ref source, elementOffset * (nuint)PerTypeValues.TypeSize); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, int elementOffset) => ref ILImpl.SubtractByteOffset(ref source, (nint)elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void* Subtract(void* source, int elementOffset) => (byte*)source - (elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, nint elementOffset) => ref ILImpl.SubtractByteOffset(ref source, elementOffset * PerTypeValues.TypeSize); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, nuint elementOffset) => ref ILImpl.SubtractByteOffset(ref source, elementOffset * (nuint)PerTypeValues.TypeSize); + +#else + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static int SizeOf() => ILImpl.SizeOf(); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, int elementOffset) => ref ILImpl.Add(ref source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void* Add(void* source, int elementOffset) => ILImpl.Add(source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, nint elementOffset) => ref ILImpl.Add(ref source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Add(ref T source, nuint elementOffset) => ref ILImpl.Add(ref source, elementOffset); + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, int elementOffset) => ref ILImpl.Subtract(ref source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static void* Subtract(void* source, int elementOffset) => ILImpl.Subtract(source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, nint elementOffset) => ref ILImpl.Subtract(ref source, elementOffset); + [MethodImpl(MethodImplOptionsEx.AggressiveInlining), NonVersionable] + public static ref T Subtract(ref T source, nuint elementOffset) => ref ILImpl.Subtract(ref source, elementOffset); + +#endif +} \ No newline at end of file diff --git a/src/MonoMod.Backports/System/NonVersionableAttribute.cs b/src/MonoMod.Backports/System/NonVersionableAttribute.cs new file mode 100644 index 00000000..7834361d --- /dev/null +++ b/src/MonoMod.Backports/System/NonVersionableAttribute.cs @@ -0,0 +1,7 @@ +namespace System +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + internal sealed class NonVersionableAttribute : Attribute + { + } +} diff --git a/src/MonoMod.Core/IDetourFactory.cs b/src/MonoMod.Core/IDetourFactory.cs index 2d8170b3..463c9744 100644 --- a/src/MonoMod.Core/IDetourFactory.cs +++ b/src/MonoMod.Core/IDetourFactory.cs @@ -79,9 +79,10 @@ public static class DetourFactory public static unsafe IDetourFactory Current { [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] - get => Helpers.GetOrInit(ref lazyCurrent, &CreateDefaultFactory); + get => Helpers.GetOrInit(ref lazyCurrent, createDefaultFactoryFunc); } + private static readonly Func createDefaultFactoryFunc = CreateDefaultFactory; private static PlatformTripleDetourFactory CreateDefaultFactory() => new(PlatformTriple.Current); diff --git a/src/MonoMod.Core/Platforms/Architectures/x86Arch.cs b/src/MonoMod.Core/Platforms/Architectures/x86Arch.cs index 81284ad8..60999060 100644 --- a/src/MonoMod.Core/Platforms/Architectures/x86Arch.cs +++ b/src/MonoMod.Core/Platforms/Architectures/x86Arch.cs @@ -11,10 +11,11 @@ internal sealed class x86Arch : IArchitecture public ArchitectureFeature Features => ArchitectureFeature.CreateAltEntryPoint; private BytePatternCollection? lazyKnownMethodThunks; - public unsafe BytePatternCollection KnownMethodThunks => Helpers.GetOrInit(ref lazyKnownMethodThunks, &CreateKnownMethodThunks); + public unsafe BytePatternCollection KnownMethodThunks => Helpers.GetOrInit(ref lazyKnownMethodThunks, createKnownMethodThunksFunc); public IAltEntryFactory AltEntryFactory { get; } + private static readonly Func createKnownMethodThunksFunc = CreateKnownMethodThunks; private static BytePatternCollection CreateKnownMethodThunks() { const ushort An = BytePattern.SAnyValue; diff --git a/src/MonoMod.Core/Platforms/Architectures/x86_64Arch.cs b/src/MonoMod.Core/Platforms/Architectures/x86_64Arch.cs index 19e7400a..2de03bf3 100644 --- a/src/MonoMod.Core/Platforms/Architectures/x86_64Arch.cs +++ b/src/MonoMod.Core/Platforms/Architectures/x86_64Arch.cs @@ -13,10 +13,11 @@ internal sealed class x86_64Arch : IArchitecture public ArchitectureFeature Features => ArchitectureFeature.Immediate64 | ArchitectureFeature.CreateAltEntryPoint; private BytePatternCollection? lazyKnownMethodThunks; - public unsafe BytePatternCollection KnownMethodThunks => Helpers.GetOrInit(ref lazyKnownMethodThunks, &CreateKnownMethodThunks); + public unsafe BytePatternCollection KnownMethodThunks => Helpers.GetOrInit(ref lazyKnownMethodThunks, createKnownMethodThunksFunc); public IAltEntryFactory AltEntryFactory { get; } + private static readonly Func createKnownMethodThunksFunc = CreateKnownMethodThunks; private static BytePatternCollection CreateKnownMethodThunks() { const ushort An = BytePattern.SAnyValue; diff --git a/src/MonoMod.Core/Platforms/PlatformTriple.cs b/src/MonoMod.Core/Platforms/PlatformTriple.cs index eb75f20a..2fea542d 100644 --- a/src/MonoMod.Core/Platforms/PlatformTriple.cs +++ b/src/MonoMod.Core/Platforms/PlatformTriple.cs @@ -117,8 +117,9 @@ public static ISystem CreateCurrentSystem() /// /// This is automatically constructed on first access, according to the values returned by . /// - public static unsafe PlatformTriple Current => Helpers.GetOrInitWithLock(ref lazyCurrent, lazyCurrentLock, &CreateCurrent); + public static unsafe PlatformTriple Current => Helpers.GetOrInitWithLock(ref lazyCurrent, lazyCurrentLock, createCurrentFunc); + private static readonly Func createCurrentFunc = CreateCurrent; private static PlatformTriple CreateCurrent() { var sys = CreateCurrentSystem(); diff --git a/src/MonoMod.Core/Platforms/Runtimes/Core21Runtime.cs b/src/MonoMod.Core/Platforms/Runtimes/Core21Runtime.cs index 7b37451f..46b9b890 100644 --- a/src/MonoMod.Core/Platforms/Runtimes/Core21Runtime.cs +++ b/src/MonoMod.Core/Platforms/Runtimes/Core21Runtime.cs @@ -39,11 +39,12 @@ internal class Core21Runtime : CoreBaseRuntime } */ + private static readonly Func createJitHookHelpersFunc = CreateJitHookHelpers; private static JitHookHelpersHolder CreateJitHookHelpers(Core21Runtime self) => new(self); private readonly object sync = new(); private JitHookHelpersHolder? lazyJitHookHelpers; - protected unsafe JitHookHelpersHolder JitHookHelpers => Helpers.GetOrInitWithLock(ref lazyJitHookHelpers, sync, &CreateJitHookHelpers, this); + protected unsafe JitHookHelpersHolder JitHookHelpers => Helpers.GetOrInitWithLock(ref lazyJitHookHelpers, sync, createJitHookHelpersFunc, this); // src/inc/corinfo.h line 216 // 0ba106c8-81a0-407f-99a1-928448c1eb62 diff --git a/src/MonoMod.ILHelpers/CompatibilitySuppressions.xml b/src/MonoMod.ILHelpers/CompatibilitySuppressions.xml index 3656039a..464a886f 100644 --- a/src/MonoMod.ILHelpers/CompatibilitySuppressions.xml +++ b/src/MonoMod.ILHelpers/CompatibilitySuppressions.xml @@ -1,31 +1,47 @@  - - CP0001 - T:System.Runtime.CompilerServices.Unsafe + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) + lib/net35/MonoMod.ILHelpers.dll + lib/net35/MonoMod.ILHelpers.dll + true + + + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) + lib/net452/MonoMod.ILHelpers.dll + lib/net452/MonoMod.ILHelpers.dll + true + + + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) lib/net5.0/MonoMod.ILHelpers.dll - lib/net6.0/MonoMod.ILHelpers.dll + lib/net5.0/MonoMod.ILHelpers.dll + true - CP1002 - System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null - left + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) + lib/net6.0/MonoMod.ILHelpers.dll lib/net6.0/MonoMod.ILHelpers.dll + true - CP1002 - System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null - left - lib/net6.0/MonoMod.ILHelpers.dll + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) + lib/net7.0/MonoMod.ILHelpers.dll + lib/net7.0/MonoMod.ILHelpers.dll true - CP1002 - System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null - lib/net6.0/MonoMod.ILHelpers.dll - right + CP0002 + M:MonoMod.ILHelpers.UnboxAnyUnsafe``1(System.Object@) + lib/netstandard2.0/MonoMod.ILHelpers.dll + lib/netstandard2.0/MonoMod.ILHelpers.dll + true CP1002 diff --git a/src/MonoMod.ILHelpers/MonoMod.ILHelpers.il b/src/MonoMod.ILHelpers/MonoMod.ILHelpers.il index 93f31ab6..8b76173e 100644 --- a/src/MonoMod.ILHelpers/MonoMod.ILHelpers.il +++ b/src/MonoMod.ILHelpers/MonoMod.ILHelpers.il @@ -1,102 +1,70 @@ -#include "version.h" - -#ifdef NET35 -#define FUNC_ASSEMBLY "System.Core" -.assembly extern FUNC_ASSEMBLY -{ - .publickeytoken = CORE_PUBKEY_TOKEN - .ver 3:5:0:0 -} -#else -#define FUNC_ASSEMBLY "CORE_ASSEMBLY" -#endif - -.class public abstract auto ansi sealed beforefieldinit MonoMod.ILHelpers - extends [CORE_ASSEMBLY]System.Object -{ - .method public hidebysig static !!T TailCallDelegatePtr(native int source) cil managed aggressiveinlining - { - .maxstack 8 - ldarg.0 - tail. - calli !!T() - ret - } // end of method Unsafe::Read - - .method public hidebysig static !!T TailCallFunc(class [FUNC_ASSEMBLY]System.Func`1 func) cil managed aggressiveinlining - { - .maxstack 8 - ldarg.0 - tail. - callvirt instance !0 class [FUNC_ASSEMBLY]System.Func`1::Invoke() - ret - } - - .method public hidebysig static !!T& ObjectAsRef(object obj) cil managed aggressiveinlining +#include "version.h" + +#ifdef NET35 +#define FUNC_ASSEMBLY "System.Core" +.assembly extern FUNC_ASSEMBLY +{ + .publickeytoken = CORE_PUBKEY_TOKEN + .ver 3:5:0:0 +} +#else +#define FUNC_ASSEMBLY "CORE_ASSEMBLY" +#endif + +.class public abstract auto ansi sealed beforefieldinit MonoMod.ILHelpers + extends [CORE_ASSEMBLY]System.Object +{ + .method public hidebysig static !!T TailCallDelegatePtr(native int source) cil managed aggressiveinlining + { + .maxstack 8 + ldarg.0 + //tail. // The tail prefix on calli seems to be considered by many tools to be invalid. + calli !!T() + ret + } // end of method Unsafe::Read + + .method public hidebysig static !!T TailCallFunc(class [FUNC_ASSEMBLY]System.Func`1 func) cil managed aggressiveinlining + { + .maxstack 8 + ldarg.0 + tail. + callvirt instance !0 class [FUNC_ASSEMBLY]System.Func`1::Invoke() + ret + } + + .method public hidebysig static !!T& ObjectAsRef(object obj) cil managed aggressiveinlining { - .maxstack 1 - .locals ( + .maxstack 1 + .locals ( object pinned pin -#ifndef netcoreapp - , !!T** refPtr +#ifndef netcoreapp + , !!T** refPtr , !!T& finalRef -#endif +#endif ) - // pin obj + // pin obj ldarg obj stloc pin - + #ifdef netcoreapp // return ref *Unsafe.BitCast(pin); - ldloc pin - conv.u -#else + ldloc pin + conv.u +#else // see docs/RuntimeIssueNotes.md - "`fixed` on strings in old Mono" for why this is necessary - // T* ptr = *(T**)(&pin); - ldloca pin - conv.u - stloc refPtr - ldloc refPtr - ldind.i + // T* ptr = *(T**)(&pin); + ldloca pin + conv.u + stloc refPtr + ldloc refPtr + ldind.i // return Unsafe.AsRef(ptr); - // see the comments inside that function for why don't just immediately ret - stloc finalRef - ldloc finalRef + // see the comments inside that function for why don't just immediately ret + stloc finalRef + ldloc finalRef #endif - ret - } - - .method public hidebysig static !!T& UnboxAnyUnsafe(object& 'box') cil managed aggressiveinlining - { - .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( - 01 00 02 00 00 - ) - - .maxstack 8 - .locals init ( - [0] !!T - ) - - // if (default(T) == null) - ldloca.s 0 - initobj !!T - ldloc.0 - box !!T - ldnull - ceq - brfalse ValType - - // it's a reference type, so we just return the ref like Unsafe.As - ldarg.0 - ret - - ValType: - // it's a value type, so we want to unbox and return the ref - ldarg.0 - ldind.ref - unbox !!T - ret - } + ret + } } \ No newline at end of file diff --git a/src/MonoMod.ILHelpers/MonoMod.ILHelpers.ilproj b/src/MonoMod.ILHelpers/MonoMod.ILHelpers.ilproj index d7f6bf36..6ad3de21 100644 --- a/src/MonoMod.ILHelpers/MonoMod.ILHelpers.ilproj +++ b/src/MonoMod.ILHelpers/MonoMod.ILHelpers.ilproj @@ -1,11 +1,40 @@  - - A collection of IL helpers for MonoMod, including a backport of System.Runtime.CompilerServices.Unsafe. + DO NOT REFERENCE THIS PACKAGE DIRECTLY! Reference MonoMod.Backports instead. + + + $(BackportsTargetFrameworks) 1.1.0 1.0.0 + + + + + + + + + + \ No newline at end of file diff --git a/src/MonoMod.ILHelpers/System.Runtime.CompilerServices.Unsafe.il b/src/MonoMod.ILHelpers/System.Runtime.CompilerServices.Unsafe.il index e087c714..99f9440e 100644 --- a/src/MonoMod.ILHelpers/System.Runtime.CompilerServices.Unsafe.il +++ b/src/MonoMod.ILHelpers/System.Runtime.CompilerServices.Unsafe.il @@ -7,10 +7,23 @@ // =============== CLASS MEMBERS DECLARATION =================== +.assembly extern MonoMod.Backports { } + +#ifdef NETSTANDARD2_1_OR_GREATER + #define UNSAFE_ILHELPERS +#endif +#ifdef NETCOREAPP1_0_OR_GREATER + #define UNSAFE_ILHELPERS +#endif + #ifdef NET6_0_OR_GREATER #ifdef NET6_0 -.assembly extern System.Runtime.CompilerServices.Unsafe { .ver CORE_ASSEMBLY_VERSION } +.assembly extern System.Runtime.CompilerServices.Unsafe +{ + .publickeytoken = CORE_PUBKEY_TOKEN + .ver CORE_ASSEMBLY_VERSION +} #endif .class extern forwarder System.Runtime.CompilerServices.Unsafe @@ -24,10 +37,21 @@ #endif } +.class extern forwarder MonoMod.Backports.ILHelpers.UnsafeRaw { .assembly extern MonoMod.Backports } + #else // TODO: nullable annotations (ugh) +#ifdef UNSAFE_ILHELPERS +// we define SRCS.Unsafe in ILHelpers, and forward UnsafeRaw to Backports, which forwards back here. +.class extern forwarder MonoMod.Backports.ILHelpers.UnsafeRaw { .assembly extern MonoMod.Backports } .class public abstract auto ansi sealed beforefieldinit System.Runtime.CompilerServices.Unsafe +#else +// we define SRCS.Unsafe in Backports to handle some runtime issues, forward to it here, +// and Backports uses some of UnsafeRaw to actually implement it +.class extern forwarder System.Runtime.CompilerServices.Unsafe { .assembly extern MonoMod.Backports } +.class public abstract auto ansi sealed beforefieldinit MonoMod.Backports.ILHelpers.UnsafeRaw +#endif extends [CORE_ASSEMBLY]System.Object { .method public hidebysig static !!T Read(void* source) cil managed aggressiveinlining @@ -324,6 +348,10 @@ .method public hidebysig static !!T& Add(!!T& source, native int elementOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) .maxstack 8 ldarg.0 ldarg.1 @@ -335,11 +363,11 @@ .method public hidebysig static !!T& Add(!!T& source, native uint elementOffset) cil managed aggressiveinlining { + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .param [2] .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 ldarg.0 ldarg.1 @@ -352,6 +380,10 @@ .method public hidebysig static !!T& AddByteOffset(!!T& source, native int byteOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) .maxstack 8 ldarg.0 ldarg.1 @@ -361,11 +393,11 @@ .method public hidebysig static !!T& AddByteOffset(!!T& source, native uint byteOffset) cil managed aggressiveinlining { + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .param [2] .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 ldarg.0 ldarg.1 @@ -402,6 +434,10 @@ .method public hidebysig static !!T& Subtract(!!T& source, native int elementOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) .maxstack 8 ldarg.0 ldarg.1 @@ -413,11 +449,11 @@ .method public hidebysig static !!T& Subtract(!!T& source, native uint elementOffset) cil managed aggressiveinlining { + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .param [2] .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 ldarg.0 ldarg.1 @@ -430,6 +466,10 @@ .method public hidebysig static !!T& SubtractByteOffset(!!T& source, native int byteOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) .maxstack 8 ldarg.0 ldarg.1 @@ -439,11 +479,11 @@ .method public hidebysig static !!T& SubtractByteOffset(!!T& source, native uint byteOffset) cil managed aggressiveinlining { + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .param [2] .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 ldarg.0 ldarg.1 @@ -454,6 +494,10 @@ .method public hidebysig static native int ByteOffset(!!T& origin, !!T& target) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .param [0] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) .maxstack 8 ldarg.1 ldarg.0 diff --git a/src/MonoMod.SourceGen.Internal/AnalyzerReleases.Unshipped.md b/src/MonoMod.SourceGen.Internal/AnalyzerReleases.Unshipped.md index 41c50d0f..2a4c8bb7 100644 --- a/src/MonoMod.SourceGen.Internal/AnalyzerReleases.Unshipped.md +++ b/src/MonoMod.SourceGen.Internal/AnalyzerReleases.Unshipped.md @@ -9,4 +9,6 @@ MM.ILOverload.BadKind | | Error | ILOverloadGenerator MM.ILOverload.NoFile | | Error | ILOverloadGenerator MM0001 | Build | Warning | AssemblyInfoGenerator MM0002 | Build | Warning | AssemblyInfoGenerator -MMA001 | Stability | Error | DoNotPinStrings \ No newline at end of file +MMA001 | RuntimeIssues | Error | DoNotPinStrings +MMA002 | RuntimeIssues | Warning | DoNotSizeofGenerics +MMA003 | RuntimeIssues | Warning | DoNotSizeofGenerics \ No newline at end of file diff --git a/src/MonoMod.SourceGen.Internal/Analyzers/DoNotPinStrings.cs b/src/MonoMod.SourceGen.Internal/Analyzers/DoNotPinStrings.cs index df9fdb9f..62a05fda 100644 --- a/src/MonoMod.SourceGen.Internal/Analyzers/DoNotPinStrings.cs +++ b/src/MonoMod.SourceGen.Internal/Analyzers/DoNotPinStrings.cs @@ -12,7 +12,7 @@ public sealed class DoNotPinStrings : DiagnosticAnalyzer "MMA001", "Do not pin strings, as it may crash some older Mono runtimes", "Do not pin strings, as it may crash some older Mono runtimes (see docs/RuntimeIssueNotes.md). Pin a span instead.", - "Stability", + "RuntimeIssues", DiagnosticSeverity.Error, isEnabledByDefault: true); diff --git a/src/MonoMod.SourceGen.Internal/Analyzers/DoNotSizeofGenerics.cs b/src/MonoMod.SourceGen.Internal/Analyzers/DoNotSizeofGenerics.cs new file mode 100644 index 00000000..3ac96f5f --- /dev/null +++ b/src/MonoMod.SourceGen.Internal/Analyzers/DoNotSizeofGenerics.cs @@ -0,0 +1,50 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using System.Collections.Immutable; + +namespace MonoMod.SourceGen.Internal.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class DoNotSizeofGenerics : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor DoNotSizeofGeneric = new( + "MMA002", + "Do not use the sizeof() operator on a generic parameter", + "On some old Mono runtimes, sizeof(T) always returns sizeof(IntPtr). See docs/RuntimeIssueNotes.md.", + "RuntimeIssues", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + private static readonly DiagnosticDescriptor DoNotUseUnsafeSizeOf = new( + "MMA003", + "Do not use Unsafe.SizeOf()", + "On some old Mono runtimes, the sizeof opcode always returns sizeof(IntPtr) on generic parameters, " + + "which Unsafe.SizeOf() always has.. See docs/RuntimeIssueNotes.md.", + "RuntimeIssues", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Create(DoNotSizeofGeneric, DoNotUseUnsafeSizeOf); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", + Justification = "Roslyn always passes a non-null context")] + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics); + + // normal sizeof operator + context.RegisterOperationAction(ctx => + { + var sizeofOp = (ISizeOfOperation)ctx.Operation; + + if (sizeofOp.TypeOperand.TypeKind is TypeKind.TypeParameter) + { + ctx.ReportDiagnostic(Diagnostic.Create(DoNotSizeofGeneric, sizeofOp.Syntax.GetLocation())); + } + }, OperationKind.SizeOf); + } + } +} diff --git a/src/MonoMod.Utils/DynamicReferenceManager.cs b/src/MonoMod.Utils/DynamicReferenceManager.cs index ce08140c..9396bfbd 100644 --- a/src/MonoMod.Utils/DynamicReferenceManager.cs +++ b/src/MonoMod.Utils/DynamicReferenceManager.cs @@ -114,7 +114,7 @@ private static unsafe DataScope AllocReferenceStruct(in [MethodImpl(MethodImplOptionsEx.AggressiveOptimization)] public static DataScope AllocReference(in T? value, out DynamicReferenceCell cellRef) { - if (default(T) == null) + if (!typeof(T).IsValueType) { return AllocReferenceClass(Unsafe.As(ref Unsafe.AsRef(in value)), out cellRef); } @@ -197,14 +197,14 @@ private static Cell GetCell(DynamicReferenceCell cellRef) { case RefValueCell: { - Helpers.Assert(default(T) == null); + Helpers.Assert(!typeof(T).IsValueType); var c = Unsafe.As(cell); Helpers.Assert(c.Value is null or T); return ref Unsafe.As(ref c.Value!); } case ValueTypeCell: { - Helpers.Assert(default(T) != null); + Helpers.Assert(typeof(T).IsValueType); var c = (ValueCell)cell; return ref c.Value; } diff --git a/src/MonoMod.Utils/Helpers.cs b/src/MonoMod.Utils/Helpers.cs index 96e736fc..5f4fb919 100644 --- a/src/MonoMod.Utils/Helpers.cs +++ b/src/MonoMod.Utils/Helpers.cs @@ -24,22 +24,22 @@ public static void Swap(ref T a, ref T b) [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public static unsafe bool Has(this T value, T flag) where T : struct, Enum { - if (sizeof(T) == sizeof(long)) + if (Unsafe.SizeOf() == sizeof(long)) { var flagVal = Unsafe.As(ref flag); return (Unsafe.As(ref value) & flagVal) == flagVal; } - else if (sizeof(T) == sizeof(int)) + else if (Unsafe.SizeOf() == sizeof(int)) { var flagVal = Unsafe.As(ref flag); return (Unsafe.As(ref value) & flagVal) == flagVal; } - else if (sizeof(T) == sizeof(short)) + else if (Unsafe.SizeOf() == sizeof(short)) { var flagVal = Unsafe.As(ref flag); return (Unsafe.As(ref value) & flagVal) == flagVal; } - else if (sizeof(T) == sizeof(byte)) + else if (Unsafe.SizeOf() == sizeof(byte)) { var flagVal = Unsafe.As(ref flag); return (Unsafe.As(ref value) & flagVal) == flagVal; @@ -157,22 +157,48 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler } #region GetOrInit* + private static class FuncInvokeHolder + { + public static readonly Func, T> InvokeFunc = static f => f(); + } + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] + public static T GetOrInit(ref T? location, Func init) where T : class + { + if (location is not null) + return location; + return InitializeValue(ref location, FuncInvokeHolder.InvokeFunc, init); + } + + [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] + public static T GetOrInitWithLock(ref T? location, object @lock, Func init) where T : class + { + if (location is not null) + return location; + return InitializeValueWithLock(ref location, @lock, FuncInvokeHolder.InvokeFunc, init); + } + [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] - public unsafe static T GetOrInit(ref T? location, Func init) where T : class + public static T GetOrInit(ref T? location, Func init, TParam param) where T : class { + ThrowIfArgumentNull(init); if (location is not null) return location; - return InitializeValue(ref location, &ILHelpers.TailCallFunc, init); + return InitializeValue(ref location, init, param); } [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] - public unsafe static T GetOrInitWithLock(ref T? location, object @lock, Func init) where T : class + public static T GetOrInitWithLock(ref T? location, object @lock, Func init, TParam param) where T : class { + ThrowIfArgumentNull(init); if (location is not null) return location; - return InitializeValueWithLock(ref location, @lock, &ILHelpers.TailCallFunc, init); + return InitializeValueWithLock(ref location, @lock, init, param); } + /// + /// This overload may not work on some older Mono implementations, which do not have good function pointer support. + /// [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public unsafe static T GetOrInit(ref T? location, delegate* init) where T : class { @@ -181,6 +207,10 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler return InitializeValue(ref location, &ILHelpers.TailCallDelegatePtr, (IntPtr)init); } + + /// + /// This overload may not work on some older Mono implementations, which do not have good function pointer support. + /// [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public unsafe static T GetOrInitWithLock(ref T? location, object @lock, delegate* init) where T : class { @@ -189,6 +219,9 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler return InitializeValueWithLock(ref location, @lock, &ILHelpers.TailCallDelegatePtr, (IntPtr)init); } + /// + /// This overload may not work on some older Mono implementations, which do not have good function pointer support. + /// [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public unsafe static T GetOrInit(ref T? location, delegate* init, TParam obj) where T : class { @@ -197,6 +230,9 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler return InitializeValue(ref location, init, obj); } + /// + /// This overload may not work on some older Mono implementations, which do not have good function pointer support. + /// [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public unsafe static T GetOrInitWithLock(ref T? location, object @lock, delegate* init, TParam obj) where T : class { @@ -212,6 +248,13 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler return location!; } + [MethodImpl(MethodImplOptionsEx.NoInlining)] + private unsafe static T InitializeValue(ref T? location, Func init, TParam obj) where T : class + { + _ = Interlocked.CompareExchange(ref location, init(obj), null); + return location!; + } + [MethodImpl(MethodImplOptionsEx.NoInlining)] private unsafe static T InitializeValueWithLock(ref T? location, object @lock, delegate* init, TParam obj) where T : class { @@ -222,6 +265,17 @@ private static void ThrowAssertionFailed(ref AssertionInterpolatedStringHandler return location = init(obj); } } + + [MethodImpl(MethodImplOptionsEx.NoInlining)] + private unsafe static T InitializeValueWithLock(ref T? location, object @lock, Func init, TParam obj) where T : class + { + lock (@lock) + { + if (location is not null) + return location; + return location = init(obj); + } + } #endregion [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] diff --git a/src/MonoMod.Utils/ReflectionHelper.FixReflectionCache.cs b/src/MonoMod.Utils/ReflectionHelper.FixReflectionCache.cs index b887663b..772dd288 100644 --- a/src/MonoMod.Utils/ReflectionHelper.FixReflectionCache.cs +++ b/src/MonoMod.Utils/ReflectionHelper.FixReflectionCache.cs @@ -7,18 +7,17 @@ namespace MonoMod.Utils { public static partial class ReflectionHelper { - // .NET Framework can break member ordering if using Module.Resolve* on certain members. private static readonly object?[] _CacheGetterArgs = { /* MemberListType.All */ 0, /* name apparently always null? */ null }; - private static Type t_RuntimeType = + // Note: on older Mono, RuntimeType doesn't exist. That's fine; it means there's no cache to fix. + private static Type? t_RuntimeType = typeof(Type).Assembly - .GetType("System.RuntimeType") - ?? throw new InvalidOperationException("Could not find RuntimeType"); + .GetType("System.RuntimeType"); private static Type? t_RuntimeTypeCache = - t_RuntimeType.GetNestedType("RuntimeTypeCache", BindingFlags.Public | BindingFlags.NonPublic); + t_RuntimeType?.GetNestedType("RuntimeTypeCache", BindingFlags.Public | BindingFlags.NonPublic); private static PropertyInfo? p_RuntimeType_Cache = t_RuntimeTypeCache == null ? null : diff --git a/tools/Common.props b/tools/Common.props index fd6f5fb1..42a70888 100644 --- a/tools/Common.props +++ b/tools/Common.props @@ -12,6 +12,7 @@ net6.0;net5.0;net7.0;net8.0;netstandard2.0;net35;net452 + $(TargetFrameworks);netstandard2.1;netcoreapp2.1;netcoreapp3.0;netcoreapp3.1 diff --git a/tools/Common.targets b/tools/Common.targets index 91dbe439..d69f5ce5 100644 --- a/tools/Common.targets +++ b/tools/Common.targets @@ -7,5 +7,20 @@ + + + + <_PropertiesToGet Remove="@(_PropertiesToGet)" /> + + + + + <_PropertiesToGet Include="$(PropertyNames)" /> + + + + + + diff --git a/tools/NuGet.props b/tools/NuGet.props index 07acb596..2642f90e 100644 --- a/tools/NuGet.props +++ b/tools/NuGet.props @@ -22,10 +22,6 @@ false - - - - diff --git a/tools/NuGet.targets b/tools/NuGet.targets index d0e73270..353e39e1 100644 --- a/tools/NuGet.targets +++ b/tools/NuGet.targets @@ -30,7 +30,7 @@ - + README.md @@ -40,6 +40,11 @@ + + + + +