From d5f114134487eca03f6d3791383e454020a13143 Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Mon, 23 Mar 2020 17:26:55 -0500 Subject: [PATCH] Fixed EventInfo accesses to be compatible with .NET 3.5 --- .../Config/Stores/GeneratedStoreImpl.cs | 728 +++++++++--------- 1 file changed, 364 insertions(+), 364 deletions(-) diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl.cs index 2416a903..57ee0c2f 100644 --- a/IPA.Loader/Config/Stores/GeneratedStoreImpl.cs +++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl.cs @@ -15,12 +15,12 @@ using System.IO; using Boolean = IPA.Config.Data.Boolean; using System.Collections; using IPA.Utilities; -using System.ComponentModel; +using System.ComponentModel; #if NET3 using Net3_Proxy; using Array = Net3_Proxy.Array; #endif - + [assembly: InternalsVisibleTo(IPA.Config.Stores.GeneratedStore.AssemblyVisibilityTarget)] namespace IPA.Config.Stores @@ -107,16 +107,16 @@ namespace IPA.Config.Stores return ret; } - /// - /// Creates a generated store outside of the context of the config system. - /// - /// - /// See for more information about how it behaves. - /// - /// the type to wrap + /// + /// Creates a generated store outside of the context of the config system. + /// + /// + /// See for more information about how it behaves. + /// + /// the type to wrap /// a generated instance of implementing functionality described by /// - public static T Create() where T : class + public static T Create() where T : class => GeneratedStoreImpl.Create(); } @@ -139,7 +139,7 @@ namespace IPA.Config.Stores { void CopyFrom(T source, bool useLock); } - internal interface IGeneratedPropertyChanged : INotifyPropertyChanged + internal interface IGeneratedPropertyChanged : INotifyPropertyChanged { PropertyChangedEventHandler PropertyChangedEvent { get; } } @@ -172,18 +172,18 @@ namespace IPA.Config.Stores internal static MethodInfo ImplTakeReadMethod = typeof(Impl).GetMethod(nameof(ImplTakeRead)); public static void ImplTakeRead(IGeneratedStore s) => FindImpl(s).TakeRead(); - public void TakeRead() + public void TakeRead() { if (!WriteSyncObject.IsWriteLockHeld) - WriteSyncObject.EnterReadLock(); + WriteSyncObject.EnterReadLock(); } internal static MethodInfo ImplReleaseReadMethod = typeof(Impl).GetMethod(nameof(ImplReleaseRead)); public static void ImplReleaseRead(IGeneratedStore s) => FindImpl(s).ReleaseRead(); - public void ReleaseRead() + public void ReleaseRead() { - if (!WriteSyncObject.IsWriteLockHeld) - WriteSyncObject.ExitReadLock(); + if (!WriteSyncObject.IsWriteLockHeld) + WriteSyncObject.ExitReadLock(); } internal static MethodInfo ImplTakeWriteMethod = typeof(Impl).GetMethod(nameof(ImplTakeWrite)); @@ -200,57 +200,57 @@ namespace IPA.Config.Stores public IDisposable ChangeTransaction(IDisposable nest, bool takeWrite = true) => GetFreeTransaction().InitWith(this, !inChangeTransaction, nest, takeWrite && !WriteSyncObject.IsWriteLockHeld); - private ChangeTransactionObj GetFreeTransaction() - => freeTransactionObjs.Count > 0 ? freeTransactionObjs.Pop() + private ChangeTransactionObj GetFreeTransaction() + => freeTransactionObjs.Count > 0 ? freeTransactionObjs.Pop() : new ChangeTransactionObj(); // TODO: maybe sometimes clean this? private static readonly Stack freeTransactionObjs = new Stack(); - private sealed class ChangeTransactionObj : IDisposable - { - private struct Data - { - public readonly Impl impl; - public readonly bool owns; - public readonly bool ownsWrite; - public readonly IDisposable nested; - - public Data(Impl impl, bool owning, bool takeWrite, IDisposable nest) - { - this.impl = impl; owns = owning; ownsWrite = takeWrite; nested = nest; - } - } - private Data data; - - public ChangeTransactionObj InitWith(Impl impl, bool owning, IDisposable nest, bool takeWrite) - { - data = new Data(impl, owning, takeWrite, nest); - - if (data.owns) - impl.inChangeTransaction = true; - if (data.ownsWrite) - impl.TakeWrite(); - - return this; - } - - public void Dispose() => Dispose(true); - private void Dispose(bool addToStore) - { - if (data.owns) - { - data.impl.inChangeTransaction = false; - data.impl.InvokeChanged(); - } - data.nested?.Dispose(); - if (data.ownsWrite) - data.impl.ReleaseWrite(); - - if (addToStore) - freeTransactionObjs.Push(this); - } - - ~ChangeTransactionObj() => Dispose(false); + private sealed class ChangeTransactionObj : IDisposable + { + private struct Data + { + public readonly Impl impl; + public readonly bool owns; + public readonly bool ownsWrite; + public readonly IDisposable nested; + + public Data(Impl impl, bool owning, bool takeWrite, IDisposable nest) + { + this.impl = impl; owns = owning; ownsWrite = takeWrite; nested = nest; + } + } + private Data data; + + public ChangeTransactionObj InitWith(Impl impl, bool owning, IDisposable nest, bool takeWrite) + { + data = new Data(impl, owning, takeWrite, nest); + + if (data.owns) + impl.inChangeTransaction = true; + if (data.ownsWrite) + impl.TakeWrite(); + + return this; + } + + public void Dispose() => Dispose(true); + private void Dispose(bool addToStore) + { + if (data.owns) + { + data.impl.inChangeTransaction = false; + data.impl.InvokeChanged(); + } + data.nested?.Dispose(); + if (data.ownsWrite) + data.impl.ReleaseWrite(); + + if (addToStore) + freeTransactionObjs.Push(this); + } + + ~ChangeTransactionObj() => Dispose(false); } public static Impl FindImpl(IGeneratedStore store) @@ -605,11 +605,11 @@ namespace IPA.Config.Stores var GetLocal = MakeGetLocal(il); foreach (var member in structure) - { - EmitStore(il, member, il => - { - EmitLoad(il, member); // load the member - EmitCorrectMember(il, member, false, true, GetLocal); // correct it + { + EmitStore(il, member, il => + { + EmitLoad(il, member); // load the member + EmitCorrectMember(il, member, false, true, GetLocal); // correct it }); } @@ -623,144 +623,144 @@ namespace IPA.Config.Stores const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; const MethodAttributes virtualPropertyMethodAttr = propertyMethodAttr | MethodAttributes.Virtual | MethodAttributes.Final; const MethodAttributes virtualMemberMethod = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Final; - - #region INotifyPropertyChanged - MethodBuilder notifyChanged = null; - if (isINotifyPropertyChanged || hasNotifyAttribute) - { - var INotifyPropertyChanged_t = typeof(INotifyPropertyChanged); - typeBuilder.AddInterfaceImplementation(INotifyPropertyChanged_t); - - var INotifyPropertyChanged_PropertyChanged = - INotifyPropertyChanged_t.GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)); - - var PropertyChangedEventHandler_t = typeof(PropertyChangedEventHandler); - var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t.GetMethod(nameof(PropertyChangedEventHandler.Invoke)); - - var PropertyChangedEventArgs_t = typeof(PropertyChangedEventArgs); - var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t.GetConstructor(new[] { typeof(string) }); - - var Delegate_t = typeof(Delegate); - var Delegate_Combine = Delegate_t.GetMethod(nameof(Delegate.Combine), BindingFlags.Static | BindingFlags.Public, null, - new[] { Delegate_t, Delegate_t }, Array.Empty()); - var Delegate_Remove = Delegate_t.GetMethod(nameof(Delegate.Remove), BindingFlags.Static | BindingFlags.Public, null, - new[] { Delegate_t, Delegate_t }, Array.Empty()); - - var CompareExchange = typeof(Interlocked).GetMethods() - .Where(m => m.Name == nameof(Interlocked.CompareExchange)) - .Where(m => m.ContainsGenericParameters) - .Where(m => m.GetParameters().Length == 3).First() - .MakeGenericMethod(PropertyChangedEventHandler_t); - - var basePropChangedEvent = type.GetEvents() - .Where(e => e.AddMethod.GetBaseDefinition().DeclaringType == INotifyPropertyChanged_t) - .FirstOrDefault(); - var basePropChangedAdd = basePropChangedEvent?.AddMethod; - var basePropChangedRemove = basePropChangedEvent?.RemoveMethod; - - var PropertyChanged_backing = typeBuilder.DefineField("PropertyChanged", PropertyChangedEventHandler_t, FieldAttributes.Private); - - var add_PropertyChanged = typeBuilder.DefineMethod("PropertyChanged", - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, - null, new[] { PropertyChangedEventHandler_t }); - typeBuilder.DefineMethodOverride(add_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetAddMethod()); - if (basePropChangedAdd != null) - typeBuilder.DefineMethodOverride(add_PropertyChanged, basePropChangedAdd); - - { - var il = add_PropertyChanged.GetILGenerator(); - - var loopLabel = il.DefineLabel(); - var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, PropertyChanged_backing); - - il.MarkLabel(loopLabel); - il.Emit(OpCodes.Stloc, delTemp); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldflda, PropertyChanged_backing); - - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, Delegate_Combine); - il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t); - - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Call, CompareExchange); - - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Bne_Un_S, loopLabel); - - il.Emit(OpCodes.Ret); - } - - var remove_PropertyChanged = typeBuilder.DefineMethod("PropertyChanged", - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, - null, new[] { PropertyChangedEventHandler_t }); - typeBuilder.DefineMethodOverride(remove_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetRemoveMethod()); - if (basePropChangedRemove != null) - typeBuilder.DefineMethodOverride(remove_PropertyChanged, basePropChangedRemove); - - { - var il = remove_PropertyChanged.GetILGenerator(); - - var loopLabel = il.DefineLabel(); - var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, PropertyChanged_backing); - - il.MarkLabel(loopLabel); - il.Emit(OpCodes.Stloc, delTemp); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldflda, PropertyChanged_backing); - - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, Delegate_Remove); - il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t); - - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Call, CompareExchange); - - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldloc, delTemp); - il.Emit(OpCodes.Bne_Un_S, loopLabel); - - il.Emit(OpCodes.Ret); - } - - var PropertyChanged_event = typeBuilder.DefineEvent(nameof(INotifyPropertyChanged.PropertyChanged), EventAttributes.None, PropertyChangedEventHandler_t); - PropertyChanged_event.SetAddOnMethod(add_PropertyChanged); - PropertyChanged_event.SetRemoveOnMethod(remove_PropertyChanged); - - notifyChanged = typeBuilder.DefineMethod("<>NotifyChanged", - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final, null, new[] { typeof(string) }); - - { - var il = notifyChanged.GetILGenerator(); - - var invokeNonNull = il.DefineLabel(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, PropertyChanged_backing); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Brtrue, invokeNonNull); - il.Emit(OpCodes.Pop); - il.Emit(OpCodes.Ret); - - il.MarkLabel(invokeNonNull); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Newobj, PropertyChangedEventArgs_ctor); - il.Emit(OpCodes.Call, PropertyChangedEventHander_Invoke); - il.Emit(OpCodes.Ret); - } - } + + #region INotifyPropertyChanged + MethodBuilder notifyChanged = null; + if (isINotifyPropertyChanged || hasNotifyAttribute) + { + var INotifyPropertyChanged_t = typeof(INotifyPropertyChanged); + typeBuilder.AddInterfaceImplementation(INotifyPropertyChanged_t); + + var INotifyPropertyChanged_PropertyChanged = + INotifyPropertyChanged_t.GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)); + + var PropertyChangedEventHandler_t = typeof(PropertyChangedEventHandler); + var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t.GetMethod(nameof(PropertyChangedEventHandler.Invoke)); + + var PropertyChangedEventArgs_t = typeof(PropertyChangedEventArgs); + var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t.GetConstructor(new[] { typeof(string) }); + + var Delegate_t = typeof(Delegate); + var Delegate_Combine = Delegate_t.GetMethod(nameof(Delegate.Combine), BindingFlags.Static | BindingFlags.Public, null, + new[] { Delegate_t, Delegate_t }, Array.Empty()); + var Delegate_Remove = Delegate_t.GetMethod(nameof(Delegate.Remove), BindingFlags.Static | BindingFlags.Public, null, + new[] { Delegate_t, Delegate_t }, Array.Empty()); + + var CompareExchange = typeof(Interlocked).GetMethods() + .Where(m => m.Name == nameof(Interlocked.CompareExchange)) + .Where(m => m.ContainsGenericParameters) + .Where(m => m.GetParameters().Length == 3).First() + .MakeGenericMethod(PropertyChangedEventHandler_t); + + var basePropChangedEvent = type.GetEvents() + .Where(e => e.GetAddMethod().GetBaseDefinition().DeclaringType == INotifyPropertyChanged_t) + .FirstOrDefault(); + var basePropChangedAdd = basePropChangedEvent? .GetAddMethod(); + var basePropChangedRemove = basePropChangedEvent?.GetRemoveMethod(); + + var PropertyChanged_backing = typeBuilder.DefineField("PropertyChanged", PropertyChangedEventHandler_t, FieldAttributes.Private); + + var add_PropertyChanged = typeBuilder.DefineMethod("PropertyChanged", + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, + null, new[] { PropertyChangedEventHandler_t }); + typeBuilder.DefineMethodOverride(add_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetAddMethod()); + if (basePropChangedAdd != null) + typeBuilder.DefineMethodOverride(add_PropertyChanged, basePropChangedAdd); + + { + var il = add_PropertyChanged.GetILGenerator(); + + var loopLabel = il.DefineLabel(); + var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, PropertyChanged_backing); + + il.MarkLabel(loopLabel); + il.Emit(OpCodes.Stloc, delTemp); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldflda, PropertyChanged_backing); + + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, Delegate_Combine); + il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t); + + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Call, CompareExchange); + + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Bne_Un_S, loopLabel); + + il.Emit(OpCodes.Ret); + } + + var remove_PropertyChanged = typeBuilder.DefineMethod("PropertyChanged", + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, + null, new[] { PropertyChangedEventHandler_t }); + typeBuilder.DefineMethodOverride(remove_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetRemoveMethod()); + if (basePropChangedRemove != null) + typeBuilder.DefineMethodOverride(remove_PropertyChanged, basePropChangedRemove); + + { + var il = remove_PropertyChanged.GetILGenerator(); + + var loopLabel = il.DefineLabel(); + var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, PropertyChanged_backing); + + il.MarkLabel(loopLabel); + il.Emit(OpCodes.Stloc, delTemp); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldflda, PropertyChanged_backing); + + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, Delegate_Remove); + il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t); + + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Call, CompareExchange); + + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Ldloc, delTemp); + il.Emit(OpCodes.Bne_Un_S, loopLabel); + + il.Emit(OpCodes.Ret); + } + + var PropertyChanged_event = typeBuilder.DefineEvent(nameof(INotifyPropertyChanged.PropertyChanged), EventAttributes.None, PropertyChangedEventHandler_t); + PropertyChanged_event.SetAddOnMethod(add_PropertyChanged); + PropertyChanged_event.SetRemoveOnMethod(remove_PropertyChanged); + + notifyChanged = typeBuilder.DefineMethod("<>NotifyChanged", + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final, null, new[] { typeof(string) }); + + { + var il = notifyChanged.GetILGenerator(); + + var invokeNonNull = il.DefineLabel(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, PropertyChanged_backing); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Brtrue, invokeNonNull); + il.Emit(OpCodes.Pop); + il.Emit(OpCodes.Ret); + + il.MarkLabel(invokeNonNull); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Newobj, PropertyChangedEventArgs_ctor); + il.Emit(OpCodes.Call, PropertyChangedEventHander_Invoke); + il.Emit(OpCodes.Ret); + } + } #endregion #region IGeneratedStore @@ -930,18 +930,18 @@ namespace IPA.Config.Stores EmitDeserializeMember(il, member, nextLabel, il => il.Emit(OpCodes.Ldloc_S, valueLocal), GetLocal); } - il.MarkLabel(nextLabel); - - if (notifyChanged != null) - { - foreach (var member in structure) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, member.Name); - il.Emit(OpCodes.Call, notifyChanged); - } - } - + il.MarkLabel(nextLabel); + + if (notifyChanged != null) + { + foreach (var member in structure) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, member.Name); + il.Emit(OpCodes.Call, notifyChanged); + } + } + il.Emit(OpCodes.Ret); } #endregion @@ -1021,51 +1021,51 @@ namespace IPA.Config.Stores "<>Changed", virtualMemberMethod, null, Type.EmptyTypes); - typeBuilder.DefineMethodOverride(coreChanged, IGeneratedStore_Changed); - if (baseChanged != null) + typeBuilder.DefineMethodOverride(coreChanged, IGeneratedStore_Changed); + if (baseChanged != null) typeBuilder.DefineMethodOverride(coreChanged, baseChanged); { var il = coreChanged.GetILGenerator(); - if (baseChanged != null) + if (baseChanged != null) { il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, baseChanged); // call base + il.Emit(OpCodes.Call, baseChanged); // call base } - il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, Impl.ImplSignalChangedMethod); il.Emit(OpCodes.Ret); // simply call our impl's SignalChanged method and return - } + } #endregion - + #region ChangeTransaction - var coreChangeTransaction = typeBuilder.DefineMethod( - "<>ChangeTransaction", - virtualMemberMethod, - typeof(IDisposable), Type.EmptyTypes); - typeBuilder.DefineMethodOverride(coreChangeTransaction, IGeneratedStore_ChangeTransaction); - if (baseChangeTransaction != null) - typeBuilder.DefineMethodOverride(coreChangeTransaction, baseChangeTransaction); - - { - var il = coreChangeTransaction.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - if (baseChangeTransaction != null) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, baseChangeTransaction); - } - else - il.Emit(OpCodes.Ldnull); - - il.Emit(OpCodes.Tailcall); - il.Emit(OpCodes.Call, Impl.ImplChangeTransactionMethod); - il.Emit(OpCodes.Ret); - } + var coreChangeTransaction = typeBuilder.DefineMethod( + "<>ChangeTransaction", + virtualMemberMethod, + typeof(IDisposable), Type.EmptyTypes); + typeBuilder.DefineMethodOverride(coreChangeTransaction, IGeneratedStore_ChangeTransaction); + if (baseChangeTransaction != null) + typeBuilder.DefineMethodOverride(coreChangeTransaction, baseChangeTransaction); + + { + var il = coreChangeTransaction.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + if (baseChangeTransaction != null) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, baseChangeTransaction); + } + else + il.Emit(OpCodes.Ldnull); + + il.Emit(OpCodes.Tailcall); + il.Emit(OpCodes.Call, Impl.ImplChangeTransactionMethod); + il.Emit(OpCodes.Ret); + } #endregion #region IGeneratedStore @@ -1085,9 +1085,9 @@ namespace IPA.Config.Stores var startLock = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Brfalse, startLock); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, coreChangeTransaction); // take the write lock + il.Emit(OpCodes.Brfalse, startLock); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, coreChangeTransaction); // take the write lock il.Emit(OpCodes.Stloc, transactionLocal); il.MarkLabel(startLock); @@ -1108,60 +1108,60 @@ namespace IPA.Config.Stores EmitWarnException(il, $"Error while copying from member {member.Name}"); il.EndExceptionBlock(); - } - - if (notifyChanged != null) - { - foreach (var member in structure) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, member.Name); - il.Emit(OpCodes.Call, notifyChanged); - } - } - + } + + if (notifyChanged != null) + { + foreach (var member in structure) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, member.Name); + il.Emit(OpCodes.Call, notifyChanged); + } + } + var endLock = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Brfalse, endLock); - il.Emit(OpCodes.Ldloc, transactionLocal); + il.Emit(OpCodes.Brfalse, endLock); + il.Emit(OpCodes.Ldloc, transactionLocal); il.Emit(OpCodes.Callvirt, IDisposable_Dispose); il.MarkLabel(endLock); il.Emit(OpCodes.Ret); } #endregion #endregion - - #region base.CopyFrom - if (baseCopyFrom != null) - { - var pubCopyFrom = typeBuilder.DefineMethod( - baseCopyFrom.Name, - virtualMemberMethod, - null, new[] { type }); - typeBuilder.DefineMethodOverride(pubCopyFrom, baseCopyFrom); - - { - var il = pubCopyFrom.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, coreChangeTransaction); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Call, copyFrom); // call internal - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, baseCopyFrom); // call base - - il.Emit(OpCodes.Tailcall); - il.Emit(OpCodes.Callvirt, IDisposable_Dispose); // dispose transaction (which calls changed) - il.Emit(OpCodes.Ret); - } - } - #endregion - + + #region base.CopyFrom + if (baseCopyFrom != null) + { + var pubCopyFrom = typeBuilder.DefineMethod( + baseCopyFrom.Name, + virtualMemberMethod, + null, new[] { type }); + typeBuilder.DefineMethodOverride(pubCopyFrom, baseCopyFrom); + + { + var il = pubCopyFrom.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, coreChangeTransaction); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Call, copyFrom); // call internal + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, baseCopyFrom); // call base + + il.Emit(OpCodes.Tailcall); + il.Emit(OpCodes.Callvirt, IDisposable_Dispose); // dispose transaction (which calls changed) + il.Emit(OpCodes.Ret); + } + } + #endregion + #region Members foreach (var member in structure.Where(m => m.IsVirtual)) { // IsVirtual implies !IsField @@ -1220,18 +1220,18 @@ namespace IPA.Config.Stores EmitCorrectMember(il, member, false, false, GetLocal); il.Emit(OpCodes.Call, set); - il.BeginFinallyBlock(); - + il.BeginFinallyBlock(); + il.Emit(OpCodes.Ldloc, transactionLocal); il.Emit(OpCodes.Callvirt, IDisposable_Dispose); il.EndExceptionBlock(); - if (notifyChanged != null) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, member.Name); - il.Emit(OpCodes.Call, notifyChanged); + if (notifyChanged != null) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, member.Name); + il.Emit(OpCodes.Call, notifyChanged); } il.Emit(OpCodes.Ret); } @@ -1247,8 +1247,8 @@ namespace IPA.Config.Stores ).Compile(); return (creatorDel, genType); - } - + } + #region Logs private static readonly MethodInfo LogErrorMethod = typeof(GeneratedStoreImpl).GetMethod(nameof(LogError), BindingFlags.NonPublic | BindingFlags.Static); internal static void LogError(Type expected, Type found, string message) @@ -1264,9 +1264,9 @@ namespace IPA.Config.Stores internal static void LogWarningException(Exception exception) { Logger.config.Warn(exception); - } - #endregion - + } + #endregion + #region Correction private static bool NeedsCorrection(SerializedMemberInfo member) { @@ -1291,29 +1291,29 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Call, member.Nullable_HasValue.GetGetMethod()); il.Emit(OpCodes.Brfalse, endLabel); il.Emit(OpCodes.Call, member.Nullable_Value.GetGetMethod()); - } - - // TODO: impl the rest of this - - // currently the only thing for this is where expect == Map, so do generate shit + } + + // TODO: impl the rest of this + + // currently the only thing for this is where expect == Map, so do generate shit var copyFrom = typeof(IGeneratedStore<>).MakeGenericType(member.Type).GetMethod(nameof(IGeneratedStore.CopyFrom)); var noCreate = il.DefineLabel(); - var valLocal = GetLocal(member.Type); - - if (!alwaysNew) - { - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, endLabel); // our input is already something we like + var valLocal = GetLocal(member.Type); + + if (!alwaysNew) + { + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, endLabel); // our input is already something we like } il.Emit(OpCodes.Stloc, valLocal); - if (!alwaysNew) - { - EmitLoad(il, member, il => il.Emit(OpCodes.Ldarg_0)); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, noCreate); - il.Emit(OpCodes.Pop); + if (!alwaysNew) + { + EmitLoad(il, member, il => il.Emit(OpCodes.Ldarg_0)); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, noCreate); + il.Emit(OpCodes.Pop); } EmitCreateChildGenerated(il, member.Type); il.MarkLabel(noCreate); @@ -1329,11 +1329,11 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Newobj, member.Nullable_Construct); il.MarkLabel(endLabel); - } + } #endregion - - #region Utility - + + #region Utility + private delegate LocalBuilder GetLocal(Type type, int idx = 0); private static GetLocal MakeGetLocal(ILGenerator il) @@ -1615,28 +1615,28 @@ namespace IPA.Config.Stores // for now, we assume that its a generated type implementing IGeneratedStore var IGeneratedStore_Serialize = typeof(IGeneratedStore).GetMethod(nameof(IGeneratedStore.Serialize)); - var IGeneratedStoreT_CopyFrom = typeof(IGeneratedStore<>).MakeGenericType(member.Type) - .GetMethod(nameof(IGeneratedStore.CopyFrom)); - - if (!member.IsVirtual) - { - var noCreate = il.DefineLabel(); - var stlocal = GetLocal(member.Type); - - // first check to make sure that this is an IGeneratedStore, because we don't control assignments to it - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, noCreate); - il.Emit(OpCodes.Stloc, stlocal); - EmitCreateChildGenerated(il, member.Type); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldloc, stlocal); - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Callvirt, IGeneratedStoreT_CopyFrom); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Stloc, stlocal); - EmitStore(il, member, il => il.Emit(OpCodes.Ldloc, stlocal)); - il.MarkLabel(noCreate); + var IGeneratedStoreT_CopyFrom = typeof(IGeneratedStore<>).MakeGenericType(member.Type) + .GetMethod(nameof(IGeneratedStore.CopyFrom)); + + if (!member.IsVirtual) + { + var noCreate = il.DefineLabel(); + var stlocal = GetLocal(member.Type); + + // first check to make sure that this is an IGeneratedStore, because we don't control assignments to it + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, noCreate); + il.Emit(OpCodes.Stloc, stlocal); + EmitCreateChildGenerated(il, member.Type); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Ldloc, stlocal); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Callvirt, IGeneratedStoreT_CopyFrom); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc, stlocal); + EmitStore(il, member, il => il.Emit(OpCodes.Ldloc, stlocal)); + il.MarkLabel(noCreate); } il.Emit(OpCodes.Callvirt, IGeneratedStore_Serialize); } @@ -1681,11 +1681,11 @@ namespace IPA.Config.Stores var valuel = GetLocal(srcType, 0); var noCreate = il.DefineLabel(); - il.Emit(OpCodes.Stloc, valuel); - EmitLoad(il, member, il => il.Emit(OpCodes.Ldarg_0)); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, noCreate); + il.Emit(OpCodes.Stloc, valuel); + EmitLoad(il, member, il => il.Emit(OpCodes.Ldarg_0)); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, noCreate); il.Emit(OpCodes.Pop); EmitCreateChildGenerated(il, member.Type); il.MarkLabel(noCreate); @@ -1760,16 +1760,16 @@ namespace IPA.Config.Stores if (member.IsGenericConverter) { var fromValueBase = member.ConverterBase.GetMethod(nameof(ValueConverter.FromValue), - new[] { typeof(Value), typeof(object) }); - var fromValue = member.Converter.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + new[] { typeof(Value), typeof(object) }); + var fromValue = member.Converter.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .FirstOrDefault(m => m.GetBaseDefinition() == fromValueBase) ?? fromValueBase; il.Emit(OpCodes.Call, fromValue); } else { var fromValueBase = typeof(IValueConverter).GetMethod(nameof(IValueConverter.FromValue), - new[] { typeof(Value), typeof(object) }); - var fromValue = member.Converter.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + new[] { typeof(Value), typeof(object) }); + var fromValue = member.Converter.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .FirstOrDefault(m => m.GetBaseDefinition() == fromValueBase) ?? fromValueBase; il.Emit(OpCodes.Call, fromValue); if (member.Type.IsValueType)