From 8745ef190bba1413d8f9133083069c0ff0640175 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sat, 20 Dec 2014 04:16:02 +0000 Subject: [PATCH] fix stuff not compiling --- BizHawk.Common/DeepEquality.cs | 2 +- .../BinaryQuickSerializer.cs | 187 ++++++++++++++++++ .../BizHawk.Emulation.Common.csproj | 1 + .../Consoles/WonderSwan/WonderSwan.cs | 15 +- 4 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 BizHawk.Emulation.Common/BinaryQuickSerializer.cs diff --git a/BizHawk.Common/DeepEquality.cs b/BizHawk.Common/DeepEquality.cs index 820cd2f696..04aa0359b9 100644 --- a/BizHawk.Common/DeepEquality.cs +++ b/BizHawk.Common/DeepEquality.cs @@ -34,7 +34,7 @@ namespace BizHawk.Common /// /// /// - private static IEnumerable GetAllFields(Type t) + public static IEnumerable GetAllFields(Type t) { while (t != null) { diff --git a/BizHawk.Emulation.Common/BinaryQuickSerializer.cs b/BizHawk.Emulation.Common/BinaryQuickSerializer.cs new file mode 100644 index 0000000000..97b791ac44 --- /dev/null +++ b/BizHawk.Emulation.Common/BinaryQuickSerializer.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Reflection.Emit; +using System.Linq.Expressions; +using System.IO; +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using System.Collections.Concurrent; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Common +{ + public class BinaryQuickSerializer + { + // fields are serialized/deserialized in their memory order as reported by Marshal.OffsetOf + // to do anything useful, passed targets should be [StructLayout.Sequential] or [StructLayout.Explicit] + + #region reflection infrastructure + private static MethodInfo FromExpression(Expression e) + { + var caller = e as MethodCallExpression; + if (caller == null) + throw new ArgumentException("Expression must be a method call"); + return caller.Method; + } + + private static MethodInfo Method(Expression f) + { + return FromExpression(f.Body); + } + private static MethodInfo Method(Expression> f) + { + return FromExpression(f.Body); + } + + private static Dictionary readhandlers = new Dictionary(); + private static Dictionary writehandlers = new Dictionary(); + + private static void AddR(Expression> f) + { + var method = Method(f); + if (!typeof(T).IsAssignableFrom(method.ReturnType)) + throw new InvalidOperationException("Type mismatch"); + readhandlers.Add(typeof(T), method); + } + private static void AddW(Expression> f) + { + var method = Method(f); + if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T))) + throw new InvalidOperationException("Type mismatch"); + writehandlers.Add(typeof(T), Method(f)); + } + + static BinaryQuickSerializer() + { + AddR(r => r.ReadBoolean()); + AddW(r => r.Write(false)); + + AddR(r => r.ReadSByte()); + AddW(r => r.Write((sbyte)0)); + + AddR(r => r.ReadByte()); + AddW(r => r.Write((byte)0)); + + AddR(r => r.ReadInt16()); + AddW(r => r.Write((short)0)); + + AddR(r => r.ReadUInt16()); + AddW(r => r.Write((ushort)0)); + + AddR(r => r.ReadInt32()); + AddW(r => r.Write((int)0)); + + AddR(r => r.ReadUInt32()); + AddW(r => r.Write((uint)0)); + + AddR(r => r.ReadInt64()); + AddW(r => r.Write((long)0)); + + AddR(r => r.ReadUInt64()); + AddW(r => r.Write((ulong)0)); + + } + + private delegate void Reader(object target, BinaryReader r); + private delegate void Writer(object target, BinaryWriter w); + + private class SerializationFactory + { + public Type Type; + public Reader Read; + public Writer Write; + } + + private static SerializationFactory CreateSer(Type t) + { + var fields = DeepEquality.GetAllFields(t) + //.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this + .OrderBy(fi => (int)Marshal.OffsetOf(t, fi.Name)) + .ToList(); + + foreach (var field in DeepEquality.GetAllFields(t)) + { + Console.WriteLine("{0} @{1}", field.Name, field.GetManagedOffset()); + } + + var rmeth = new DynamicMethod(t.Name + "_r", null, new[] { typeof(object), typeof(BinaryReader) }, true); + var wmeth = new DynamicMethod(t.Name + "_w", null, new[] { typeof(object), typeof(BinaryWriter) }, true); + + { + var il = rmeth.GetILGenerator(); + var target = il.DeclareLocal(t); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, target); + + foreach (var field in fields) + { + il.Emit(OpCodes.Ldloc, target); + il.Emit(OpCodes.Ldarg_1); + MethodInfo m; + if (!readhandlers.TryGetValue(field.FieldType, out m)) + throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType); + il.Emit(OpCodes.Callvirt, m); + il.Emit(OpCodes.Stfld, field); + Console.WriteLine("(R) {0} {1}: {2}", field.Name, field.FieldType, m); + } + il.Emit(OpCodes.Ret); + } + { + var il = wmeth.GetILGenerator(); + var target = il.DeclareLocal(t); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, target); + + foreach (var field in fields) + { + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldloc, target); + il.Emit(OpCodes.Ldfld, field); + MethodInfo m; + if (!writehandlers.TryGetValue(field.FieldType, out m)) + throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType); + il.Emit(OpCodes.Callvirt, m); + Console.WriteLine("(W) {0} {1}: {2}", field.Name, field.FieldType, m); + } + il.Emit(OpCodes.Ret); + } + + return new SerializationFactory + { + Type = t, + Read = (Reader)rmeth.CreateDelegate(typeof(Reader)), + Write = (Writer)wmeth.CreateDelegate(typeof(Writer)) + }; + } + #endregion + + private static IDictionary sers = + new ConcurrentDictionary(); + + private static SerializationFactory GetFactory(Type t) + { + SerializationFactory f; + if (!sers.TryGetValue(t, out f)) + { + f = CreateSer(t); + sers[t] = f; + } + return f; + } + + public static void Read(object target, BinaryReader r) + { + GetFactory(target.GetType()).Read(target, r); + } + + public static void Write(object target, BinaryWriter w) + { + GetFactory(target.GetType()).Write(target, w); + } + } +} diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index 4c7ff0f34a..d3ffcfb00f 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -60,6 +60,7 @@ + diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index b625a091fc..3cbe563dd0 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -268,13 +268,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan writer.Write(savebuff.Length); writer.Write(savebuff); - // other variables - /* - writer.Write(IsLagFrame); - writer.Write(LagCount); - writer.Write(Frame); - */ - var d = new TextStateData(); SaveTextStateData(d); BinaryQuickSerializer.Write(d, writer); @@ -289,10 +282,9 @@ namespace BizHawk.Emulation.Cores.WonderSwan if (!BizSwan.bizswan_binstateload(Core, savebuff, savebuff.Length)) throw new InvalidOperationException("bizswan_binstateload() returned false!"); - // other variables - IsLagFrame = reader.ReadBoolean(); - LagCount = reader.ReadInt32(); - Frame = reader.ReadInt32(); + var d = new TextStateData(); + BinaryQuickSerializer.Read(d, reader); + LoadTextStateData(d); } public byte[] SaveStateBinary() @@ -602,7 +594,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan public void DiscardSamples() { sbuffcontains = 0; - new DiscSystem.Disc().Dispose(); } #endregion