using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo(MsgPack.CompiledPacker.MethodBuilderPacker.AssemblyName)] //======================================================================================================== // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //using NUnit.Framework; namespace Test { using System; using System.Collections.Generic; using System.Linq; using Test.Share; using MsgPack; using Microshaoft; //using System.Diagnostics; //using Microsoft.VisualStudio.TestTools.UnitTesting; //[TestFixture] public class Class1 { static void Main(string[] args) { Class1 c = new Class1(); int iterations = 1000; CodeTimer.ParallelTime ( "MsgPack ObjectPacker 并行测试", iterations, () => { c.Test_ObjectPacker(); } ); CodeTimer.Time ( "MsgPack ObjectPacker 串行测试", iterations, () => { c.Test_ObjectPacker(); } ); CodeTimer.ParallelTime ( "MsgPack CompiledPacker 并行测试", iterations, () => { c.Test_CompiledPacker(); } ); CodeTimer.Time ( "MsgPack CompiledPacker 串行测试", iterations, () => { c.Test_CompiledPacker(); } ); //CodeTimer.ParallelTime // ( // "MsgPack BoxingPacker 并行测试", // iterations, // () => // { // c.Test_BoxingPacker(); // } // ); //CodeTimer.Time // ( // "MsgPack BoxingPacker 串行测试", // iterations, // () => // { // c.Test_BoxingPacker(); // } // ); CodeTimer.ParallelTime ( "MsgPack ObjectPacker/CompiledPacker 并行测试", iterations, () => { c.Test_HybridPacker(); } ); CodeTimer.Time ( "MsgPack ObjectPacker/CompiledPacker 串行测试", iterations, () => { c.Test_HybridPacker(); } ); Console.WriteLine("Hello World"); Console.WriteLine(Environment.Version.ToString()); Console.ReadLine(); } public void Test_HybridPacker() { ObjectMsgPackHeader header = new ObjectMsgPackHeader(); header.From = "Microshaoft"; header.ToList = new string[] { "m1", "m2", "m3" }; //header.Instance = header; ObjectMsgPackBody body = new ObjectMsgPackBody(); body.Parameter1 = "asdasdas"; body.Parameter2 = 1000; body.ParameterX = new List<string>(); body.ParameterX.Add("aaaaa"); body.ParameterX.Add("bbbbb"); //body.Instance = body; byte[] buffer; ObjectMsgPack message = new ObjectMsgPack(); message.Header = new CompiledPacker().Pack(header); message.Body = new ObjectPacker().Pack(body); message.SenderID = "asdasd"; message.Signature = new byte[10]; message.TimeStamp = "2012-03-22"; buffer = new ObjectPacker().Pack(message); //Console.WriteLine("HybridPacker Buffer.Length {0}", buffer.Length); ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer); ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header); ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body); Print(x, y, z); } public void Test_BoxingPacker() { ObjectMsgPackHeader header = new ObjectMsgPackHeader(); header.From = "Microshaoft"; header.ToList = new string[] { "m1", "m2", "m3" }; //header.Instance = header; ObjectMsgPackBody body = new ObjectMsgPackBody(); body.Parameter1 = "asdasdas"; body.Parameter2 = 1000; body.ParameterX = new List<string>(); body.ParameterX.Add("aaaaa"); body.ParameterX.Add("bbbbb"); //body.Instance = body; byte[] buffer; ObjectMsgPack message = new ObjectMsgPack(); message.Header = new BoxingPacker().Pack(header); message.Body = new BoxingPacker().Pack(body); message.SenderID = "asdasd"; message.Signature = new byte[10]; message.TimeStamp = "2012-03-22"; buffer = new BoxingPacker().Pack(message); //Console.WriteLine("BoxingPacker Buffer.Length {0}", buffer.Length); ObjectMsgPack x = (ObjectMsgPack) new BoxingPacker().Unpack(buffer); ObjectMsgPackHeader y = (ObjectMsgPackHeader) new BoxingPacker().Unpack(x.Header); ObjectMsgPackBody z = (ObjectMsgPackBody) new BoxingPacker().Unpack(x.Body); Print(x, y, z); } public void Test_CompiledPacker() { ObjectMsgPackHeader header = new ObjectMsgPackHeader(); header.From = "Microshaoft"; header.ToList = new string[] { "m1", "m2", "m3" }; //header.Instance = header; ObjectMsgPackBody body = new ObjectMsgPackBody(); body.Parameter1 = "asdasdas"; body.Parameter2 = 1000; body.ParameterX = new List<string>(); body.ParameterX.Add("aaaaa"); body.ParameterX.Add("bbbbb"); //body.Instance = body; byte[] buffer; ObjectMsgPack message = new ObjectMsgPack(); message.Header = new CompiledPacker().Pack(header); message.Body = new CompiledPacker().Pack(body); message.SenderID = "asdasd"; message.Signature = new byte[10]; message.TimeStamp = "2012-03-22"; buffer = new CompiledPacker().Pack(message); //Console.WriteLine("CompiledPacker Buffer.Length {0}", buffer.Length); ObjectMsgPack x = new CompiledPacker().Unpack<ObjectMsgPack>(buffer); ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header); ObjectMsgPackBody z = new CompiledPacker().Unpack<ObjectMsgPackBody>(x.Body); Print(x, y, z); } public void Test_ObjectPacker() { ObjectMsgPackHeader header = new ObjectMsgPackHeader(); header.From = "Microshaoft"; header.ToList = new string[] { "m1", "m2", "m3" }; //header.Instance = header; ObjectMsgPackBody body = new ObjectMsgPackBody(); body.Parameter1 = "asdasdas"; body.Parameter2 = 1000; body.ParameterX = new List<string>(); body.ParameterX.Add("aaaaa"); body.ParameterX.Add("bbbbb"); //body.Instance = body; byte[] buffer; ObjectMsgPack message = new ObjectMsgPack(); message.Header = new ObjectPacker().Pack(header); message.Body = new ObjectPacker().Pack(body); message.SenderID = "asdasd"; message.Signature = new byte[10]; message.TimeStamp = "2012-03-22"; buffer = new ObjectPacker().Pack(message); //Console.WriteLine("ObjectPacker Buffer.Length {0}", buffer.Length); ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer); ObjectMsgPackHeader y = new ObjectPacker().Unpack<ObjectMsgPackHeader>(x.Header); ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body); Print(x, y, z); } public void Print(ObjectMsgPack x, ObjectMsgPackHeader y, ObjectMsgPackBody z) { return; Console.WriteLine(x.SenderID); Console.WriteLine(x.Signature.Length); Console.WriteLine(x.TimeStamp); Console.WriteLine(y.From); y.ToList.ToList().ForEach ( s => { Console.WriteLine(s); } ); Console.WriteLine(z.Parameter1); Console.WriteLine(z.Parameter12); Console.WriteLine(z.FF.F1); Console.WriteLine(z.FF.F2); z.Parameter3.ToList().ForEach ( s => { Console.WriteLine(s); } ); } } } namespace Microshaoft { using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using System.Runtime.InteropServices; public static class CodeTimer { public static void Initialize() { Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; Thread.CurrentThread.Priority = ThreadPriority.Highest; Time("", 1, () => { }); } public static void ParallelTime(string name, int iteration, Action action) { if (string.IsNullOrEmpty(name)) { return; } // 1. ConsoleColor currentForeColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(name); // 2. GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); int[] gcCounts = new int[GC.MaxGeneration + 1]; for (int i = 0; i <= GC.MaxGeneration; i++) { gcCounts[i] = GC.CollectionCount(i); } // 3. Stopwatch watch = new Stopwatch(); watch.Start(); ulong cycleCount = GetCycleCount(); Parallel.For ( 0 , iteration , i => { action(); } ); ulong cpuCycles = GetCycleCount() - cycleCount; watch.Stop(); // 4. Console.ForegroundColor = currentForeColor; Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms"); Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0")); // 5. for (int i = 0; i <= GC.MaxGeneration; i++) { int count = GC.CollectionCount(i) - gcCounts[i]; Console.WriteLine("\tGen " + i + ": \t\t" + count); } Console.WriteLine(); } public static void Time(string name, int iteration, Action action) { if (string.IsNullOrEmpty(name)) { return; } // 1. ConsoleColor currentForeColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(name); // 2. GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); int[] gcCounts = new int[GC.MaxGeneration + 1]; for (int i = 0; i <= GC.MaxGeneration; i++) { gcCounts[i] = GC.CollectionCount(i); } // 3. Stopwatch watch = new Stopwatch(); watch.Start(); ulong cycleCount = GetCycleCount(); for (int i = 0; i < iteration; i++) { action(); } ulong cpuCycles = GetCycleCount() - cycleCount; watch.Stop(); // 4. Console.ForegroundColor = currentForeColor; Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms"); Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0")); // 5. for (int i = 0; i <= GC.MaxGeneration; i++) { int count = GC.CollectionCount(i) - gcCounts[i]; Console.WriteLine("\tGen " + i + ": \t\t" + count); } Console.WriteLine(); } private static ulong GetCycleCount() { ulong cycleCount = 0; QueryThreadCycleTime(GetCurrentThread(), ref cycleCount); return cycleCount; } [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime); [DllImport("kernel32.dll")] static extern IntPtr GetCurrentThread(); } } //=============================================================================================================== namespace Test.Share { using System; using System.Collections.Generic; public class ObjectMsgPack { public string SenderID; public string TimeStamp; public byte[] Signature; public byte[] Header; public byte[] Body; } public class ObjectMsgPackHeader { //public ObjectMsgPack Container; //public ObjectMsgPackHeader Instance; public string From; public string[] ToList; } public class ObjectMsgPackBody { //public ObjectMsgPack Container; //public ObjectMsgPackBody Instance; public string Parameter1 = "aaaa"; public int Parameter2 = 100; public string Parameter3 = "aaaa"; public int Parameter4 = 100; public string Parameter5 = "aaaa"; public int Parameter6 = 100; public string Parameter7 = "aaaa"; public int Parameter8 = 100; public string Parameter9 = "aaaa"; public int Parameter10 = 100; public string Parameter11 = "aaaa"; public int Parameter12 = -101; public List<string> ParameterX; public ComplexType FF = new ComplexType(); } public class ComplexType { public string F1 = "asdasd"; public DateTime F2 = DateTime.Parse("2012-03-30 00:00:00.00000"); } } //================================================================================================ namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // public enum TypePrefixes : byte { PositiveFixNum = 0x00, // 0x00 - 0x7f NegativeFixNum = 0xe0, // 0xe0 - 0xff Nil = 0xc0, False = 0xc2, True = 0xc3, Float = 0xca, Double = 0xcb, UInt8 = 0xcc, UInt16 = 0xcd, UInt32 = 0xce, UInt64 = 0xcf, Int8 = 0xd0, Int16 = 0xd1, Int32 = 0xd2, Int64 = 0xd3, Raw16 = 0xda, Raw32 = 0xdb, Array16 = 0xdc, Array32 = 0xdd, Map16 = 0xde, Map32 = 0xdf, FixRaw = 0xa0, // 0xa0 - 0xbf FixArray = 0x90, // 0x90 - 0x9f FixMap = 0x80, // 0x80 - 0x8f } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections.Generic; using System.Reflection; public class ReflectionCacheEntry { const BindingFlags FieldBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField; public ReflectionCacheEntry(Type t) { FieldInfo[] fields = t.GetFields(FieldBindingFlags); IDictionary<string, FieldInfo> map = new Dictionary<string, FieldInfo>(fields.Length); for (int i = 0; i < fields.Length; i++) { FieldInfo f = fields[i]; string name = f.Name; int pos; if (name[0] == '<' && (pos = name.IndexOf('>')) > 1) { name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab> } map[name] = f; } FieldMap = map; } public IDictionary<string, FieldInfo> FieldMap { get; private set; } } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections.Generic; public static class ReflectionCache { static Dictionary<Type, ReflectionCacheEntry> _cache; static ReflectionCache() { _cache = new Dictionary<Type, ReflectionCacheEntry>(); } public static ReflectionCacheEntry Lookup(Type type) { ReflectionCacheEntry entry; lock (_cache) { if (_cache.TryGetValue(type, out entry)) { return entry; } } entry = new ReflectionCacheEntry(type); lock (_cache) { _cache[type] = entry; } return entry; } public static void RemoveCache(Type type) { lock (_cache) { _cache.Remove(type); } } public static void Clear() { lock (_cache) { _cache.Clear(); } } } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.Serialization; using System.Text; public class ObjectPacker { byte[] _buf = new byte[64]; Encoding _encoding = Encoding.UTF8; static Dictionary<Type, PackDelegate> PackerMapping; static Dictionary<Type, UnpackDelegate> UnpackerMapping; delegate void PackDelegate(ObjectPacker packer, MsgPackWriter writer, object o); delegate object UnpackDelegate(ObjectPacker packer, MsgPackReader reader); static ObjectPacker() { PackerMapping = new Dictionary<Type, PackDelegate>(); UnpackerMapping = new Dictionary<Type, UnpackDelegate>(); PackerMapping.Add(typeof(string), StringPacker); UnpackerMapping.Add(typeof(string), StringUnpacker); } public byte[] Pack(object o) { using (MemoryStream ms = new MemoryStream()) { Pack(ms, o); return ms.ToArray(); } } public void Pack(Stream strm, object o) { if (o != null && o.GetType().IsPrimitive) throw new NotSupportedException(); MsgPackWriter writer = new MsgPackWriter(strm); Pack(writer, o); } void Pack(MsgPackWriter writer, object o) { if (o == null) { writer.WriteNil(); return; } Type t = o.GetType(); if (t.IsPrimitive) { if (t.Equals(typeof(int))) { writer.Write((int)o); } else if (t.Equals(typeof(uint))) { writer.Write((uint)o); } else if (t.Equals(typeof(float))) { writer.Write((float)o); } else if (t.Equals(typeof(double))) { writer.Write((double)o); } else if (t.Equals(typeof(long))) { writer.Write((long)o); } else if (t.Equals(typeof(ulong))) { writer.Write((ulong)o); } else if (t.Equals(typeof(bool))) { writer.Write((bool)o); } else if (t.Equals(typeof(byte))) { writer.Write((byte)o); } else if (t.Equals(typeof(sbyte))) { writer.Write((sbyte)o); } else if (t.Equals(typeof(short))) { writer.Write((short)o); } else if (t.Equals(typeof(ushort))) { writer.Write((ushort)o); } else if (t.Equals(typeof(char))) { writer.Write((ushort)(char)o); } else { throw new NotSupportedException(); } return; } PackDelegate packer; if (PackerMapping.TryGetValue(t, out packer)) { packer(this, writer, o); return; } if (t.IsArray) { Array ary = (Array)o; writer.WriteArrayHeader(ary.Length); for (int i = 0; i < ary.Length; i++) Pack(writer, ary.GetValue(i)); return; } ReflectionCacheEntry entry = ReflectionCache.Lookup(t); writer.WriteMapHeader(entry.FieldMap.Count); foreach (KeyValuePair<string, FieldInfo> pair in entry.FieldMap) { writer.Write(pair.Key, _buf); object v = pair.Value.GetValue(o); if (pair.Value.FieldType.IsInterface && v != null) { writer.WriteArrayHeader(2); writer.Write(v.GetType().FullName); } Pack(writer, v); } } public T Unpack<T>(byte[] buf) { return Unpack<T>(buf, 0, buf.Length); } public T Unpack<T>(byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream(buf, offset, size)) { return Unpack<T>(ms); } } public T Unpack<T>(Stream strm) { if (typeof(T).IsPrimitive) throw new NotSupportedException(); MsgPackReader reader = new MsgPackReader(strm); return (T)Unpack(reader, typeof(T)); } public object Unpack(Type type, byte[] buf) { return Unpack(type, buf, 0, buf.Length); } public object Unpack(Type type, byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream(buf, offset, size)) { return Unpack(type, ms); } } public object Unpack(Type type, Stream strm) { if (type.IsPrimitive) throw new NotSupportedException(); MsgPackReader reader = new MsgPackReader(strm); return Unpack(reader, type); } object Unpack(MsgPackReader reader, Type t) { if (t.IsPrimitive) { if (!reader.Read()) throw new FormatException(); if (t.Equals(typeof(int)) && reader.IsSigned()) return reader.ValueSigned; else if (t.Equals(typeof(uint)) && reader.IsUnsigned()) return reader.ValueUnsigned; else if (t.Equals(typeof(float)) && reader.Type == TypePrefixes.Float) return reader.ValueFloat; else if (t.Equals(typeof(double)) && reader.Type == TypePrefixes.Double) return reader.ValueDouble; else if (t.Equals(typeof(long))) { if (reader.IsSigned64()) return reader.ValueSigned64; if (reader.IsSigned()) return (long)reader.ValueSigned; } else if (t.Equals(typeof(ulong))) { if (reader.IsUnsigned64()) return reader.ValueUnsigned64; if (reader.IsUnsigned()) return (ulong)reader.ValueUnsigned; } else if (t.Equals(typeof(bool)) && reader.IsBoolean()) return (reader.Type == TypePrefixes.True); else if (t.Equals(typeof(byte)) && reader.IsUnsigned()) return (byte)reader.ValueUnsigned; else if (t.Equals(typeof(sbyte)) && reader.IsSigned()) return (sbyte)reader.ValueSigned; else if (t.Equals(typeof(short)) && reader.IsSigned()) return (short)reader.ValueSigned; else if (t.Equals(typeof(ushort)) && reader.IsUnsigned()) return (ushort)reader.ValueUnsigned; else if (t.Equals(typeof(char)) && reader.IsUnsigned()) return (char)reader.ValueUnsigned; else throw new NotSupportedException(); } UnpackDelegate unpacker; if (UnpackerMapping.TryGetValue(t, out unpacker)) return unpacker(this, reader); if (t.IsArray) { if (!reader.Read() || (!reader.IsArray() && reader.Type != TypePrefixes.Nil)) throw new FormatException(); if (reader.Type == TypePrefixes.Nil) return null; Type et = t.GetElementType(); Array ary = Array.CreateInstance(et, (int)reader.Length); for (int i = 0; i < ary.Length; i++) ary.SetValue(Unpack(reader, et), i); return ary; } if (!reader.Read()) throw new FormatException(); if (reader.Type == TypePrefixes.Nil) return null; if (t.IsInterface) { if (reader.Type != TypePrefixes.FixArray && reader.Length != 2) throw new FormatException(); if (!reader.Read() || !reader.IsRaw()) throw new FormatException(); CheckBufferSize((int)reader.Length); reader.ReadValueRaw(_buf, 0, (int)reader.Length); t = Type.GetType(Encoding.UTF8.GetString(_buf, 0, (int)reader.Length)); if (!reader.Read() || reader.Type == TypePrefixes.Nil) throw new FormatException(); } if (!reader.IsMap()) throw new FormatException(); object o = FormatterServices.GetUninitializedObject(t); ReflectionCacheEntry entry = ReflectionCache.Lookup(t); int members = (int)reader.Length; for (int i = 0; i < members; i++) { if (!reader.Read() || !reader.IsRaw()) throw new FormatException(); CheckBufferSize((int)reader.Length); reader.ReadValueRaw(_buf, 0, (int)reader.Length); string name = Encoding.UTF8.GetString(_buf, 0, (int)reader.Length); FieldInfo f; if (!entry.FieldMap.TryGetValue(name, out f)) throw new FormatException(); f.SetValue(o, Unpack(reader, f.FieldType)); } IDeserializationCallback callback = o as IDeserializationCallback; if (callback != null) callback.OnDeserialization(this); return o; } void CheckBufferSize(int size) { if (_buf.Length < size) Array.Resize<byte>(ref _buf, size); } static void StringPacker(ObjectPacker packer, MsgPackWriter writer, object o) { writer.Write(Encoding.UTF8.GetBytes((string)o)); } static object StringUnpacker(ObjectPacker packer, MsgPackReader reader) { if (!reader.Read()) throw new FormatException(); if (reader.Type == TypePrefixes.Nil) return null; if (!reader.IsRaw()) throw new FormatException(); packer.CheckBufferSize((int)reader.Length); reader.ReadValueRaw(packer._buf, 0, (int)reader.Length); return Encoding.UTF8.GetString(packer._buf, 0, (int)reader.Length); } } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.IO; using System.Text; public class MsgPackWriter { Stream _strm; Encoding _encoding = Encoding.UTF8; Encoder _encoder = Encoding.UTF8.GetEncoder(); byte[] _tmp = new byte[9]; byte[] _buf = new byte[64]; public MsgPackWriter(Stream strm) { _strm = strm; } public void Write(byte x) { if (x < 128) { _strm.WriteByte(x); } else { byte[] tmp = _tmp; tmp[0] = 0xcc; tmp[1] = x; _strm.Write(tmp, 0, 2); } } public void Write(ushort x) { if (x < 0x100) { Write((byte)x); } else { byte[] tmp = _tmp; tmp[0] = 0xcd; tmp[1] = (byte)(x >> 8); tmp[2] = (byte)x; _strm.Write(tmp, 0, 3); } } public void Write(char x) { Write((ushort)x); } public void Write(uint x) { if (x < 0x10000) { Write((ushort)x); } else { byte[] tmp = _tmp; tmp[0] = 0xce; tmp[1] = (byte)(x >> 24); tmp[2] = (byte)(x >> 16); tmp[3] = (byte)(x >> 8); tmp[4] = (byte)x; _strm.Write(tmp, 0, 5); } } public void Write(ulong x) { if (x < 0x100000000) { Write((uint)x); } else { byte[] tmp = _tmp; tmp[0] = 0xcf; tmp[1] = (byte)(x >> 56); tmp[2] = (byte)(x >> 48); tmp[3] = (byte)(x >> 40); tmp[4] = (byte)(x >> 32); tmp[5] = (byte)(x >> 24); tmp[6] = (byte)(x >> 16); tmp[7] = (byte)(x >> 8); tmp[8] = (byte)x; _strm.Write(tmp, 0, 9); } } public void Write(sbyte x) { if (x >= -32 && x <= -1) { _strm.WriteByte((byte)(0xe0 | (byte)x)); } else if (x >= 0 && x <= 127) { _strm.WriteByte((byte)x); } else { byte[] tmp = _tmp; tmp[0] = 0xd0; tmp[1] = (byte)x; _strm.Write(tmp, 0, 2); } } public void Write(short x) { if (x >= sbyte.MinValue && x <= sbyte.MaxValue) { Write((sbyte)x); } else { byte[] tmp = _tmp; tmp[0] = 0xd1; tmp[1] = (byte)(x >> 8); tmp[2] = (byte)x; _strm.Write(tmp, 0, 3); } } public void Write(int x) { if (x >= short.MinValue && x <= short.MaxValue) { Write((short)x); } else { byte[] tmp = _tmp; tmp[0] = 0xd2; tmp[1] = (byte)(x >> 24); tmp[2] = (byte)(x >> 16); tmp[3] = (byte)(x >> 8); tmp[4] = (byte)x; _strm.Write(tmp, 0, 5); } } public void Write(long x) { if (x >= int.MinValue && x <= int.MaxValue) { Write((int)x); } else { byte[] tmp = _tmp; tmp[0] = 0xd3; tmp[1] = (byte)(x >> 56); tmp[2] = (byte)(x >> 48); tmp[3] = (byte)(x >> 40); tmp[4] = (byte)(x >> 32); tmp[5] = (byte)(x >> 24); tmp[6] = (byte)(x >> 16); tmp[7] = (byte)(x >> 8); tmp[8] = (byte)x; _strm.Write(tmp, 0, 9); } } public void WriteNil() { _strm.WriteByte(0xc0); } public void Write(bool x) { _strm.WriteByte((byte)(x ? 0xc3 : 0xc2)); } public void Write(float x) { byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う? byte[] tmp = _tmp; tmp[0] = 0xca; if (BitConverter.IsLittleEndian) { tmp[1] = raw[3]; tmp[2] = raw[2]; tmp[3] = raw[1]; tmp[4] = raw[0]; } else { tmp[1] = raw[0]; tmp[2] = raw[1]; tmp[3] = raw[2]; tmp[4] = raw[3]; } _strm.Write(tmp, 0, 5); } public void Write(double x) { byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う? byte[] tmp = _tmp; tmp[0] = 0xcb; if (BitConverter.IsLittleEndian) { tmp[1] = raw[7]; tmp[2] = raw[6]; tmp[3] = raw[5]; tmp[4] = raw[4]; tmp[5] = raw[3]; tmp[6] = raw[2]; tmp[7] = raw[1]; tmp[8] = raw[0]; } else { tmp[1] = raw[0]; tmp[2] = raw[1]; tmp[3] = raw[2]; tmp[4] = raw[3]; tmp[5] = raw[4]; tmp[6] = raw[5]; tmp[7] = raw[6]; tmp[8] = raw[7]; } _strm.Write(tmp, 0, 9); } public void Write(byte[] bytes) { WriteRawHeader(bytes.Length); _strm.Write(bytes, 0, bytes.Length); } public void WriteRawHeader(int N) { WriteLengthHeader(N, 32, 0xa0, 0xda, 0xdb); } public void WriteArrayHeader(int N) { WriteLengthHeader(N, 16, 0x90, 0xdc, 0xdd); } public void WriteMapHeader(int N) { WriteLengthHeader(N, 16, 0x80, 0xde, 0xdf); } void WriteLengthHeader(int N, int fix_length, byte fix_prefix, byte len16bit_prefix, byte len32bit_prefix) { if (N < fix_length) { _strm.WriteByte((byte)(fix_prefix | N)); } else { byte[] tmp = _tmp; int header_len; if (N < 0x10000) { tmp[0] = len16bit_prefix; tmp[1] = (byte)(N >> 8); tmp[2] = (byte)N; header_len = 3; } else { tmp[0] = len32bit_prefix; tmp[1] = (byte)(N >> 24); tmp[2] = (byte)(N >> 16); tmp[3] = (byte)(N >> 8); tmp[4] = (byte)N; header_len = 5; } _strm.Write(tmp, 0, header_len); } } public void Write(string x) { Write(x, false); } public void Write(string x, bool highProbAscii) { Write(x, _buf, highProbAscii); } public void Write(string x, byte[] buf) { Write(x, buf, false); } public unsafe void Write(string x, byte[] buf, bool highProbAscii) { Encoder encoder = _encoder; fixed (char* pstr = x) fixed (byte* pbuf = buf) { if (highProbAscii && x.Length <= buf.Length) { bool isAsciiFullCompatible = true; for (int i = 0; i < x.Length; i++) { int v = (int)pstr[i]; if (v > 0x7f) { isAsciiFullCompatible = false; break; } buf[i] = (byte)v; } if (isAsciiFullCompatible) { WriteRawHeader(x.Length); _strm.Write(buf, 0, x.Length); return; } } WriteRawHeader(encoder.GetByteCount(pstr, x.Length, true)); int str_len = x.Length; char* p = pstr; int convertedChars, bytesUsed; bool completed = true; while (str_len > 0 || !completed) { encoder.Convert(p, str_len, pbuf, buf.Length, false, out convertedChars, out bytesUsed, out completed); _strm.Write(buf, 0, bytesUsed); str_len -= convertedChars; p += convertedChars; } } } } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.IO; using System.Text; public class MsgPackReader { Stream _strm; byte[] _tmp0 = new byte[8]; byte[] _tmp1 = new byte[8]; Encoding _encoding = Encoding.UTF8; Decoder _decoder = Encoding.UTF8.GetDecoder(); byte[] _buf = new byte[64]; public MsgPackReader(Stream strm) { _strm = strm; } public TypePrefixes Type { get; private set; } public bool ValueBoolean { get; private set; } public uint Length { get; private set; } public uint ValueUnsigned { get; private set; } public ulong ValueUnsigned64 { get; private set; } public int ValueSigned { get; private set; } public long ValueSigned64 { get; private set; } public float ValueFloat { get; private set; } public double ValueDouble { get; private set; } public bool IsSigned() { return this.Type == TypePrefixes.NegativeFixNum || this.Type == TypePrefixes.PositiveFixNum || this.Type == TypePrefixes.Int8 || this.Type == TypePrefixes.Int16 || this.Type == TypePrefixes.Int32; } public bool IsBoolean() { return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False; } public bool IsSigned64() { return this.Type == TypePrefixes.Int64; } public bool IsUnsigned() { return this.Type == TypePrefixes.PositiveFixNum || this.Type == TypePrefixes.UInt8 || this.Type == TypePrefixes.UInt16 || this.Type == TypePrefixes.UInt32; } public bool IsUnsigned64() { return this.Type == TypePrefixes.UInt64; } public bool IsRaw() { return this.Type == TypePrefixes.FixRaw || this.Type == TypePrefixes.Raw16 || this.Type == TypePrefixes.Raw32; } public bool IsArray() { return this.Type == TypePrefixes.FixArray || this.Type == TypePrefixes.Array16 || this.Type == TypePrefixes.Array32; } public bool IsMap() { return this.Type == TypePrefixes.FixMap || this.Type == TypePrefixes.Map16 || this.Type == TypePrefixes.Map32; } public bool Read() { byte[] tmp0 = _tmp0, tmp1 = _tmp1; int x = _strm.ReadByte(); if (x < 0) return false; // EOS if (x >= 0x00 && x <= 0x7f) { this.Type = TypePrefixes.PositiveFixNum; } else if (x >= 0xe0 && x <= 0xff) { this.Type = TypePrefixes.NegativeFixNum; } else if (x >= 0xa0 && x <= 0xbf) { this.Type = TypePrefixes.FixRaw; } else if (x >= 0x90 && x <= 0x9f) { this.Type = TypePrefixes.FixArray; } else if (x >= 0x80 && x <= 0x8f) { this.Type = TypePrefixes.FixMap; } else { this.Type = (TypePrefixes)x; } switch (this.Type) { case TypePrefixes.Nil: break; case TypePrefixes.False: ValueBoolean = false; break; case TypePrefixes.True: ValueBoolean = true; break; case TypePrefixes.Float: _strm.Read(tmp0, 0, 4); if (BitConverter.IsLittleEndian) { tmp1[0] = tmp0[3]; tmp1[1] = tmp0[2]; tmp1[2] = tmp0[1]; tmp1[3] = tmp0[0]; ValueFloat = BitConverter.ToSingle(tmp1, 0); } else { ValueFloat = BitConverter.ToSingle(tmp0, 0); } break; case TypePrefixes.Double: _strm.Read(tmp0, 0, 8); if (BitConverter.IsLittleEndian) { tmp1[0] = tmp0[7]; tmp1[1] = tmp0[6]; tmp1[2] = tmp0[5]; tmp1[3] = tmp0[4]; tmp1[4] = tmp0[3]; tmp1[5] = tmp0[2]; tmp1[6] = tmp0[1]; tmp1[7] = tmp0[0]; ValueDouble = BitConverter.ToDouble(tmp1, 0); } else { ValueDouble = BitConverter.ToDouble(tmp0, 0); } break; case TypePrefixes.NegativeFixNum: ValueSigned = (x & 0x1f) - 0x20; break; case TypePrefixes.PositiveFixNum: ValueSigned = x & 0x7f; ValueUnsigned = (uint)ValueSigned; break; case TypePrefixes.UInt8: x = _strm.ReadByte(); if (x < 0) throw new FormatException(); ValueUnsigned = (uint)x; break; case TypePrefixes.UInt16: if (_strm.Read(tmp0, 0, 2) != 2) throw new FormatException(); ValueUnsigned = ((uint)tmp0[0] << 8) | (uint)tmp0[1]; break; case TypePrefixes.UInt32: if (_strm.Read(tmp0, 0, 4) != 4) throw new FormatException(); ValueUnsigned = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3]; break; case TypePrefixes.UInt64: if (_strm.Read(tmp0, 0, 8) != 8) throw new FormatException(); ValueUnsigned64 = ((ulong)tmp0[0] << 56) | ((ulong)tmp0[1] << 48) | ((ulong)tmp0[2] << 40) | ((ulong)tmp0[3] << 32) | ((ulong)tmp0[4] << 24) | ((ulong)tmp0[5] << 16) | ((ulong)tmp0[6] << 8) | (ulong)tmp0[7]; break; case TypePrefixes.Int8: x = _strm.ReadByte(); if (x < 0) throw new FormatException(); ValueSigned = (sbyte)x; break; case TypePrefixes.Int16: if (_strm.Read(tmp0, 0, 2) != 2) throw new FormatException(); ValueSigned = (short)((tmp0[0] << 8) | tmp0[1]); break; case TypePrefixes.Int32: if (_strm.Read(tmp0, 0, 4) != 4) throw new FormatException(); ValueSigned = (tmp0[0] << 24) | (tmp0[1] << 16) | (tmp0[2] << 8) | tmp0[3]; break; case TypePrefixes.Int64: if (_strm.Read(tmp0, 0, 8) != 8) throw new FormatException(); ValueSigned64 = ((long)tmp0[0] << 56) | ((long)tmp0[1] << 48) | ((long)tmp0[2] << 40) | ((long)tmp0[3] << 32) | ((long)tmp0[4] << 24) | ((long)tmp0[5] << 16) | ((long)tmp0[6] << 8) | (long)tmp0[7]; break; case TypePrefixes.FixRaw: Length = (uint)(x & 0x1f); break; case TypePrefixes.FixArray: case TypePrefixes.FixMap: Length = (uint)(x & 0xf); break; case TypePrefixes.Raw16: case TypePrefixes.Array16: case TypePrefixes.Map16: if (_strm.Read(tmp0, 0, 2) != 2) throw new FormatException(); Length = ((uint)tmp0[0] << 8) | (uint)tmp0[1]; break; case TypePrefixes.Raw32: case TypePrefixes.Array32: case TypePrefixes.Map32: if (_strm.Read(tmp0, 0, 4) != 4) throw new FormatException(); Length = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3]; break; default: throw new FormatException(); } return true; } public int ReadValueRaw(byte[] buf, int offset, int count) { return _strm.Read(buf, offset, count); } public string ReadRawString() { return ReadRawString(_buf); } public unsafe string ReadRawString(byte[] buf) { if (this.Length < buf.Length) { if (ReadValueRaw(buf, 0, (int)this.Length) != this.Length) { throw new FormatException(); } return _encoding.GetString(buf, 0, (int)this.Length); } // Poor implementation byte[] tmp = new byte[(int)this.Length]; if (ReadValueRaw(tmp, 0, tmp.Length) != tmp.Length) throw new FormatException(); return _encoding.GetString(tmp); } } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Threading; using MsgPack.Compiler; public class CompiledPacker { static PackerBase _publicFieldPacker, _allFieldPacker; PackerBase _packer; static CompiledPacker() { _publicFieldPacker = new MethodBuilderPacker(); _allFieldPacker = new DynamicMethodPacker(); } public CompiledPacker() : this(false) { } public CompiledPacker(bool packPrivateField) { _packer = (packPrivateField ? _allFieldPacker : _publicFieldPacker); } public void Prepare<T>() { _packer.CreatePacker<T>(); _packer.CreateUnpacker<T>(); } #region Generics Pack/Unpack Methods public byte[] Pack<T>(T o) { using (MemoryStream ms = new MemoryStream()) { Pack<T>(ms, o); return ms.ToArray(); } } public void Pack<T>(Stream strm, T o) { _packer.CreatePacker<T>()(new MsgPackWriter(strm), o); } public T Unpack<T>(byte[] buf) { return Unpack<T>(buf, 0, buf.Length); } public T Unpack<T>(byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream(buf, offset, size)) { return Unpack<T>(ms); } } public T Unpack<T>(Stream strm) { return _packer.CreateUnpacker<T>()(new MsgPackReader(strm)); } #endregion #region Non-generics Pack/Unpack Methods public byte[] Pack(object o) { using (MemoryStream ms = new MemoryStream()) { Pack(ms, o); return ms.ToArray(); } } public void Pack(Stream strm, object o) { throw new NotImplementedException(); } public object Unpack(Type t, byte[] buf) { return Unpack(t, buf, 0, buf.Length); } public object Unpack(Type t, byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream(buf, offset, size)) { return Unpack(t, ms); } } public object Unpack(Type t, Stream strm) { throw new NotImplementedException(); } #endregion #region Compiled Packer Implementations public abstract class PackerBase { Dictionary<Type, Delegate> _packers = new Dictionary<Type, Delegate>(); Dictionary<Type, Delegate> _unpackers = new Dictionary<Type, Delegate>(); protected Dictionary<Type, MethodInfo> _packMethods = new Dictionary<Type, MethodInfo>(); protected Dictionary<Type, MethodInfo> _unpackMethods = new Dictionary<Type, MethodInfo>(); protected PackerBase() { DefaultPackMethods.Register(_packMethods, _unpackMethods); } public Action<MsgPackWriter, T> CreatePacker<T>() { Delegate d; lock (_packers) { if (!_packers.TryGetValue(typeof(T), out d)) { d = CreatePacker_Internal<T>(); _packers.Add(typeof(T), d); } } return (Action<MsgPackWriter, T>)d; } public Func<MsgPackReader, T> CreateUnpacker<T>() { Delegate d; lock (_unpackers) { if (!_unpackers.TryGetValue(typeof(T), out d)) { d = CreateUnpacker_Internal<T>(); _unpackers.Add(typeof(T), d); } } return (Func<MsgPackReader, T>)d; } protected abstract Action<MsgPackWriter, T> CreatePacker_Internal<T>(); protected abstract Func<MsgPackReader, T> CreateUnpacker_Internal<T>(); } public sealed class DynamicMethodPacker : PackerBase { private static MethodInfo LookupMemberMappingMethod; static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings; static DynamicMethodPacker() { UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>(); LookupMemberMappingMethod = typeof(DynamicMethodPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic); } public DynamicMethodPacker() : base() { } protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>() { DynamicMethod dm = CreatePacker(typeof(T), CreatePackDynamicMethod(typeof(T))); return (Action<MsgPackWriter, T>)dm.CreateDelegate(typeof(Action<MsgPackWriter, T>)); } protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>() { DynamicMethod dm = CreateUnpacker(typeof(T), CreateUnpackDynamicMethod(typeof(T))); return (Func<MsgPackReader, T>)dm.CreateDelegate(typeof(Func<MsgPackReader, T>)); } DynamicMethod CreatePacker(Type t, DynamicMethod dm) { ILGenerator il = dm.GetILGenerator(); _packMethods.Add(t, dm); PackILGenerator.EmitPackCode(t, dm, il, LookupMembers, FormatMemberName, LookupPackMethod); return dm; } DynamicMethod CreateUnpacker(Type t, DynamicMethod dm) { ILGenerator il = dm.GetILGenerator(); _unpackMethods.Add(t, dm); PackILGenerator.EmitUnpackCode(t, dm, il, LookupMembers, FormatMemberName, LookupUnpackMethod, LookupMemberMapping, LookupMemberMappingMethod); return dm; } static DynamicMethod CreatePackDynamicMethod(Type t) { return CreateDynamicMethod(typeof(void), new Type[] { typeof(MsgPackWriter), t }); } static DynamicMethod CreateUnpackDynamicMethod(Type t) { return CreateDynamicMethod(t, new Type[] { typeof(MsgPackReader) }); } static MemberInfo[] LookupMembers(Type t) { BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; List<MemberInfo> list = new List<MemberInfo>(); list.AddRange(t.GetFields(baseFlags)); // TODO: Add NonSerialized Attribute Filter ? return list.ToArray(); } MethodInfo LookupPackMethod(Type t) { MethodInfo mi; DynamicMethod dm; if (_packMethods.TryGetValue(t, out mi)) return mi; dm = CreatePackDynamicMethod(t); return CreatePacker(t, dm); } MethodInfo LookupUnpackMethod(Type t) { MethodInfo mi; if (_unpackMethods.TryGetValue(t, out mi)) return mi; DynamicMethod dm = CreateUnpackDynamicMethod(t); return CreateUnpacker(t, dm); } static string FormatMemberName(MemberInfo m) { if (m.MemberType != MemberTypes.Field) return m.Name; int pos; string name = m.Name; if (name[0] == '<' && (pos = name.IndexOf('>')) > 1) name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab> return name; } static int _dynamicMethodIdx = 0; static DynamicMethod CreateDynamicMethod(Type returnType, Type[] parameterTypes) { string name = "_" + Interlocked.Increment(ref _dynamicMethodIdx).ToString(); return new DynamicMethod(name, returnType, parameterTypes, true); } internal static IDictionary<string, int> LookupMemberMapping(Type t) { IDictionary<string, int> mapping; lock (UnpackMemberMappings) { if (!UnpackMemberMappings.TryGetValue(t, out mapping)) { mapping = new Dictionary<string, int>(); UnpackMemberMappings.Add(t, mapping); } } return mapping; } } public sealed class MethodBuilderPacker : PackerBase { public const string AssemblyName = "MessagePackInternalAssembly"; static AssemblyName DynamicAsmName; static AssemblyBuilder DynamicAsmBuilder; static ModuleBuilder DynamicModuleBuilder; private static MethodInfo LookupMemberMappingMethod; static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings; static MethodBuilderPacker() { UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>(); LookupMemberMappingMethod = typeof(MethodBuilderPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic); DynamicAsmName = new AssemblyName(AssemblyName); DynamicAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(DynamicAsmName, AssemblyBuilderAccess.Run); DynamicModuleBuilder = DynamicAsmBuilder.DefineDynamicModule(DynamicAsmName.Name); } public MethodBuilderPacker() : base() { } protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>() { TypeBuilder tb; MethodBuilder mb; CreatePackMethodBuilder(typeof(T), out tb, out mb); _packMethods.Add(typeof(T), mb); CreatePacker(typeof(T), mb); MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, true); return (Action<MsgPackWriter, T>)Delegate.CreateDelegate(typeof(Action<MsgPackWriter, T>), mi); } protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>() { TypeBuilder tb; MethodBuilder mb; CreateUnpackMethodBuilder(typeof(T), out tb, out mb); _unpackMethods.Add(typeof(T), mb); CreateUnpacker(typeof(T), mb); MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, false); return (Func<MsgPackReader, T>)Delegate.CreateDelegate(typeof(Func<MsgPackReader, T>), mi); } void CreatePacker(Type t, MethodBuilder mb) { ILGenerator il = mb.GetILGenerator(); PackILGenerator.EmitPackCode(t, mb, il, LookupMembers, FormatMemberName, LookupPackMethod); } void CreateUnpacker(Type t, MethodBuilder mb) { ILGenerator il = mb.GetILGenerator(); PackILGenerator.EmitUnpackCode(t, mb, il, LookupMembers, FormatMemberName, LookupUnpackMethod, LookupMemberMapping, LookupMemberMappingMethod); } MethodInfo ToCallableMethodInfo(Type t, TypeBuilder tb, bool isPacker) { Type type = tb.CreateType(); MethodInfo mi = type.GetMethod(isPacker ? "Pack" : "Unpack", BindingFlags.Static | BindingFlags.Public); if (isPacker) { _packMethods[t] = mi; } else { _unpackMethods[t] = mi; } return mi; } MethodInfo LookupPackMethod(Type t) { MethodInfo mi; TypeBuilder tb; MethodBuilder mb; if (_packMethods.TryGetValue(t, out mi)) return mi; CreatePackMethodBuilder(t, out tb, out mb); _packMethods.Add(t, mb); CreatePacker(t, mb); return ToCallableMethodInfo(t, tb, true); } MethodInfo LookupUnpackMethod(Type t) { MethodInfo mi; TypeBuilder tb; MethodBuilder mb; if (_unpackMethods.TryGetValue(t, out mi)) return mi; CreateUnpackMethodBuilder(t, out tb, out mb); _unpackMethods.Add(t, mb); CreateUnpacker(t, mb); return ToCallableMethodInfo(t, tb, false); } static string FormatMemberName(MemberInfo m) { return m.Name; } static MemberInfo[] LookupMembers(Type t) { BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public; List<MemberInfo> list = new List<MemberInfo>(); list.AddRange(t.GetFields(baseFlags)); // TODO: Add NonSerialized Attribute Filter ? return list.ToArray(); } static void CreatePackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb) { tb = DynamicModuleBuilder.DefineType(t.Name + "PackerType", TypeAttributes.Public); mb = tb.DefineMethod("Pack", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { typeof(MsgPackWriter), t }); } static void CreateUnpackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb) { tb = DynamicModuleBuilder.DefineType(t.Name + "UnpackerType", TypeAttributes.Public); mb = tb.DefineMethod("Unpack", MethodAttributes.Static | MethodAttributes.Public, t, new Type[] { typeof(MsgPackReader) }); } internal static IDictionary<string, int> LookupMemberMapping(Type t) { IDictionary<string, int> mapping; lock (UnpackMemberMappings) { if (!UnpackMemberMappings.TryGetValue(t, out mapping)) { mapping = new Dictionary<string, int>(); UnpackMemberMappings.Add(t, mapping); } } return mapping; } } #endregion #region default pack/unpack methods internal static class DefaultPackMethods { public static void Register(Dictionary<Type, MethodInfo> packMethods, Dictionary<Type, MethodInfo> unpackMethods) { RegisterPackMethods(packMethods); RegisterUnpackMethods(unpackMethods); } #region Pack static void RegisterPackMethods(Dictionary<Type, MethodInfo> packMethods) { Type type = typeof(DefaultPackMethods); MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic); string methodName = "Pack"; for (int i = 0; i < methods.Length; i++) { if (!methodName.Equals(methods[i].Name)) { continue; } ParameterInfo[] parameters = methods[i].GetParameters(); if (parameters.Length != 2 || parameters[0].ParameterType != typeof(MsgPackWriter)) { continue; } packMethods.Add(parameters[1].ParameterType, methods[i]); } } internal static void Pack(MsgPackWriter writer, string x) { if (x == null) { writer.WriteNil(); } else { writer.Write(x, false); } } #endregion #region Unpack static void RegisterUnpackMethods(Dictionary<Type, MethodInfo> unpackMethods) { BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; Type type = typeof(DefaultPackMethods); MethodInfo mi = type.GetMethod("Unpack_Signed", flags); unpackMethods.Add(typeof(sbyte), mi); unpackMethods.Add(typeof(short), mi); unpackMethods.Add(typeof(int), mi); mi = type.GetMethod("Unpack_Signed64", flags); unpackMethods.Add(typeof(long), mi); mi = type.GetMethod("Unpack_Unsigned", flags); unpackMethods.Add(typeof(byte), mi); unpackMethods.Add(typeof(ushort), mi); unpackMethods.Add(typeof(char), mi); unpackMethods.Add(typeof(uint), mi); mi = type.GetMethod("Unpack_Unsigned64", flags); unpackMethods.Add(typeof(ulong), mi); mi = type.GetMethod("Unpack_Boolean", flags); unpackMethods.Add(typeof(bool), mi); mi = type.GetMethod("Unpack_Float", flags); unpackMethods.Add(typeof(float), mi); mi = type.GetMethod("Unpack_Double", flags); unpackMethods.Add(typeof(double), mi); mi = type.GetMethod("Unpack_String", flags); unpackMethods.Add(typeof(string), mi); } internal static int Unpack_Signed(MsgPackReader reader) { if (!reader.Read() || !reader.IsSigned()) UnpackFailed(); return reader.ValueSigned; } internal static long Unpack_Signed64(MsgPackReader reader) { if (!reader.Read()) { UnpackFailed(); } if (reader.IsSigned()) { return reader.ValueSigned; } if (reader.IsSigned64()) { return reader.ValueSigned64; } UnpackFailed(); return 0; // unused } internal static uint Unpack_Unsigned(MsgPackReader reader) { if (!reader.Read() || !reader.IsUnsigned()) UnpackFailed(); return reader.ValueUnsigned; } internal static ulong Unpack_Unsigned64(MsgPackReader reader) { if (!reader.Read()) UnpackFailed(); if (reader.IsUnsigned()) return reader.ValueUnsigned; if (reader.IsUnsigned64()) return reader.ValueUnsigned64; UnpackFailed(); return 0; // unused } internal static bool Unpack_Boolean(MsgPackReader reader) { if (!reader.Read() || !reader.IsBoolean()) UnpackFailed(); return reader.ValueBoolean; } internal static float Unpack_Float(MsgPackReader reader) { if (!reader.Read() || reader.Type != TypePrefixes.Float) UnpackFailed(); return reader.ValueFloat; } internal static double Unpack_Double(MsgPackReader reader) { if (!reader.Read() || reader.Type != TypePrefixes.Double) UnpackFailed(); return reader.ValueDouble; } internal static string Unpack_String(MsgPackReader reader) { if (!reader.Read() || !reader.IsRaw()) UnpackFailed(); return reader.ReadRawString(); } internal static void UnpackFailed() { throw new FormatException(); } #endregion } #endregion } } namespace MsgPack { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; public class BoxingPacker { static Type KeyValuePairDefinitionType; static BoxingPacker() { KeyValuePairDefinitionType = typeof(KeyValuePair<object, object>).GetGenericTypeDefinition(); } public void Pack(Stream strm, object o) { MsgPackWriter writer = new MsgPackWriter(strm); Pack(writer, o); } public byte[] Pack(object o) { using (MemoryStream ms = new MemoryStream()) { Pack(ms, o); return ms.ToArray(); } } void Pack(MsgPackWriter writer, object o) { if (o == null) { writer.WriteNil(); return; } Type t = o.GetType(); if (t.IsPrimitive) { if (t.Equals(typeof(int))) writer.Write((int)o); else if (t.Equals(typeof(uint))) writer.Write((uint)o); else if (t.Equals(typeof(float))) writer.Write((float)o); else if (t.Equals(typeof(double))) writer.Write((double)o); else if (t.Equals(typeof(long))) writer.Write((long)o); else if (t.Equals(typeof(ulong))) writer.Write((ulong)o); else if (t.Equals(typeof(bool))) writer.Write((bool)o); else if (t.Equals(typeof(byte))) writer.Write((byte)o); else if (t.Equals(typeof(sbyte))) writer.Write((sbyte)o); else if (t.Equals(typeof(short))) writer.Write((short)o); else if (t.Equals(typeof(ushort))) writer.Write((ushort)o); else throw new NotSupportedException(); // char? return; } IDictionary dic = o as IDictionary; if (dic != null) { writer.WriteMapHeader(dic.Count); foreach (System.Collections.DictionaryEntry e in dic) { Pack(writer, e.Key); Pack(writer, e.Value); } return; } if (t.IsArray) { Array ary = (Array)o; Type et = t.GetElementType(); // KeyValuePair<K,V>[] (Map Type) if (et.IsGenericType && et.GetGenericTypeDefinition().Equals(KeyValuePairDefinitionType)) { PropertyInfo propKey = et.GetProperty("Key"); PropertyInfo propValue = et.GetProperty("Value"); writer.WriteMapHeader(ary.Length); for (int i = 0; i < ary.Length; i++) { object e = ary.GetValue(i); Pack(writer, propKey.GetValue(e, null)); Pack(writer, propValue.GetValue(e, null)); } return; } // Array writer.WriteArrayHeader(ary.Length); for (int i = 0; i < ary.Length; i++) Pack(writer, ary.GetValue(i)); return; } } public object Unpack(Stream strm) { MsgPackReader reader = new MsgPackReader(strm); return Unpack(reader); } public object Unpack(byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream(buf, offset, size)) { return Unpack(ms); } } public object Unpack(byte[] buf) { return Unpack(buf, 0, buf.Length); } object Unpack(MsgPackReader reader) { if (!reader.Read()) { throw new FormatException(); } switch (reader.Type) { case TypePrefixes.PositiveFixNum: case TypePrefixes.NegativeFixNum: case TypePrefixes.Int8: case TypePrefixes.Int16: case TypePrefixes.Int32: return reader.ValueSigned; case TypePrefixes.Int64: return reader.ValueSigned64; case TypePrefixes.UInt8: case TypePrefixes.UInt16: case TypePrefixes.UInt32: return reader.ValueUnsigned; case TypePrefixes.UInt64: return reader.ValueUnsigned64; case TypePrefixes.True: return true; case TypePrefixes.False: return false; case TypePrefixes.Float: return reader.ValueFloat; case TypePrefixes.Double: return reader.ValueDouble; case TypePrefixes.Nil: return null; case TypePrefixes.FixRaw: case TypePrefixes.Raw16: case TypePrefixes.Raw32: byte[] raw = new byte[reader.Length]; reader.ReadValueRaw(raw, 0, raw.Length); return raw; case TypePrefixes.FixArray: case TypePrefixes.Array16: case TypePrefixes.Array32: object[] ary = new object[reader.Length]; for (int i = 0; i < ary.Length; i++) ary[i] = Unpack(reader); return ary; case TypePrefixes.FixMap: case TypePrefixes.Map16: case TypePrefixes.Map32: IDictionary<object, object> dic = new Dictionary<object, object>((int)reader.Length); int count = (int)reader.Length; for (int i = 0; i < count; i++) { object k = Unpack(reader); object v = Unpack(reader); dic.Add(k, v); } return dic; default: throw new FormatException(); } } } } namespace MsgPack.Compiler { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // public enum VariableType { Local, Arg } } namespace MsgPack.Compiler { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System.Reflection.Emit; public class Variable { Variable(VariableType type, int index) { this.VarType = type; this.Index = index; } public static Variable CreateLocal(LocalBuilder local) { return new Variable(VariableType.Local, local.LocalIndex); } public static Variable CreateArg(int idx) { return new Variable(VariableType.Arg, idx); } public VariableType VarType { get; set; } public int Index { get; set; } } } namespace MsgPack.Compiler { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; static class PackILGenerator { #region Pack IL Generator public static void EmitPackCode ( Type type , MethodInfo mi , ILGenerator il , Func<Type, MemberInfo[]> targetMemberSelector , Func<MemberInfo, string> memberNameFormatter , Func<Type, MethodInfo> lookupPackMethod ) { if (type.IsPrimitive || type.IsInterface) { throw new NotSupportedException(); } Variable arg_writer = Variable.CreateArg(0); Variable arg_obj = Variable.CreateArg(1); Variable local_i = Variable.CreateLocal(il.DeclareLocal(typeof(int))); if (!type.IsValueType) { // null check Label notNullLabel = il.DefineLabel(); il.EmitLd(arg_obj); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.EmitLd(arg_writer); il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteNil", new Type[0])); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); } if (type.IsArray) { EmitPackArrayCode(mi, il, type, arg_writer, arg_obj, local_i, lookupPackMethod); goto FinallyProcess; } // MsgPackWriter.WriteMapHeader MemberInfo[] members = targetMemberSelector(type); il.EmitLd(arg_writer); il.EmitLdc(members.Length); il.Emit(OpCodes.Callvirt, typeof(MsgPackWriter).GetMethod("WriteMapHeader", new Type[] { typeof(int) })); for (int i = 0; i < members.Length; i++) { MemberInfo m = members[i]; Type mt = m.GetMemberType(); // write field-name il.EmitLd(arg_writer); il.EmitLdstr(memberNameFormatter(m)); il.EmitLd_True(); il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("Write", new Type[] { typeof(string), typeof(bool) })); // write value EmitPackMemberValueCode(mt, il, arg_writer, arg_obj, m, null, type, mi, lookupPackMethod); } FinallyProcess: il.Emit(OpCodes.Ret); } static void EmitPackArrayCode ( MethodInfo mi , ILGenerator il , Type t , Variable var_writer , Variable var_obj , Variable var_loop , Func<Type, MethodInfo> lookupPackMethod ) { Type et = t.GetElementType(); il.EmitLd(var_writer, var_obj); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteArrayHeader", new Type[] { typeof(int) })); Label beginLabel = il.DefineLabel(); Label exprLabel = il.DefineLabel(); // for-loop: init loop counter il.EmitLdc(0); il.EmitSt(var_loop); // jump il.Emit(OpCodes.Br_S, exprLabel); // mark begin-label il.MarkLabel(beginLabel); // write element EmitPackMemberValueCode(et, il, var_writer, var_obj, null, var_loop, t, mi, lookupPackMethod); // increment loop-counter il.EmitLd(var_loop); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.EmitSt(var_loop); // mark expression label il.MarkLabel(exprLabel); // expression il.EmitLd(var_loop, var_obj); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Blt_S, beginLabel); } /// <param name="m">(optional)</param> /// <param name="elementIdx">(optional)</param> static void EmitPackMemberValueCode(Type type, ILGenerator il, Variable var_writer, Variable var_obj, MemberInfo m, Variable elementIdx, Type currentType, MethodInfo currentMethod, Func<Type, MethodInfo> lookupPackMethod) { MethodInfo mi; il.EmitLd(var_writer, var_obj); if (m != null) il.EmitLdMember(m); if (elementIdx != null) { il.EmitLd(elementIdx); il.Emit(OpCodes.Ldelem, type); } if (type.IsPrimitive) { mi = typeof(MsgPackWriter).GetMethod("Write", new Type[] { type }); } else { if (currentType == type) { mi = currentMethod; } else { mi = lookupPackMethod(type); } } il.Emit(OpCodes.Call, mi); } #endregion #region Unpack IL Generator public static void EmitUnpackCode(Type type, MethodInfo mi, ILGenerator il, Func<Type, MemberInfo[]> targetMemberSelector, Func<MemberInfo, string> memberNameFormatter, Func<Type, MethodInfo> lookupUnpackMethod, Func<Type, IDictionary<string, int>> lookupMemberMapping, MethodInfo lookupMemberMappingMethod) { if (type.IsArray) { EmitUnpackArrayCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod); } else { EmitUnpackMapCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod, lookupMemberMapping, lookupMemberMappingMethod); } } static void EmitUnpackMapCode(Type type, MethodInfo mi, ILGenerator il, Func<Type, MemberInfo[]> targetMemberSelector, Func<MemberInfo, string> memberNameFormatter, Func<Type, MethodInfo> lookupUnpackMethod, Func<Type, IDictionary<string, int>> lookupMemberMapping, MethodInfo lookupMemberMappingMethod) { MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); MemberInfo[] members = targetMemberSelector(type); IDictionary<string, int> member_mapping = lookupMemberMapping(type); for (int i = 0; i < members.Length; i++) member_mapping.Add(memberNameFormatter(members[i]), i); Variable msgpackReader = Variable.CreateArg(0); Variable obj = Variable.CreateLocal(il.DeclareLocal(type)); Variable num_of_fields = Variable.CreateLocal(il.DeclareLocal(typeof(int))); Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int))); Variable mapping = Variable.CreateLocal(il.DeclareLocal(typeof(IDictionary<string, int>))); Variable switch_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int))); Variable var_type = Variable.CreateLocal(il.DeclareLocal(typeof(Type))); // if (!MsgPackReader.Read()) UnpackFailed (); // if (MsgPackReader.Type == TypePrefixes.Nil) return null; // if (!MsgPackReader.IsMap ()) UnpackFailed (); EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsMap"), failedMethod, true); // type = typeof (T) il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); il.EmitSt(var_type); // mapping = LookupMemberMapping (typeof (T)) il.EmitLd(var_type); il.Emit(OpCodes.Call, lookupMemberMappingMethod); il.EmitSt(mapping); // object o = FormatterServices.GetUninitializedObject (Type); il.EmitLd(var_type); il.Emit(OpCodes.Call, typeof(FormatterServices).GetMethod("GetUninitializedObject")); il.Emit(OpCodes.Castclass, type); il.EmitSt(obj); // num_of_fields = (int)reader.Length il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod()); il.EmitSt(num_of_fields); // Loop labels Label lblLoopStart = il.DefineLabel(); Label lblLoopExpr = il.DefineLabel(); // i = 0; il.EmitLdc(0); il.EmitSt(loop_idx); il.Emit(OpCodes.Br, lblLoopExpr); il.MarkLabel(lblLoopStart); /* process */ // if (!MsgPackReader.Read() || !MsgPackReader.IsRaw()) UnpackFailed(); EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsRaw"), failedMethod, false); // MsgPackReader.ReadRawString () // if (!Dictionary.TryGetValue (,)) UnpackFailed(); Label lbl3 = il.DefineLabel(); il.EmitLd(mapping); il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("ReadRawString", new Type[0])); il.Emit(OpCodes.Ldloca_S, (byte)switch_idx.Index); il.Emit(OpCodes.Callvirt, typeof(IDictionary<string, int>).GetMethod("TryGetValue")); il.Emit(OpCodes.Brtrue, lbl3); il.Emit(OpCodes.Call, failedMethod); il.MarkLabel(lbl3); // switch Label[] switchCases = new Label[members.Length]; for (int i = 0; i < switchCases.Length; i++) switchCases[i] = il.DefineLabel(); Label switchCaseEndLabel = il.DefineLabel(); il.EmitLd(switch_idx); il.Emit(OpCodes.Switch, switchCases); il.Emit(OpCodes.Call, failedMethod); for (int i = 0; i < switchCases.Length; i++) { il.MarkLabel(switchCases[i]); MemberInfo minfo = members[i]; Type mt = minfo.GetMemberType(); MethodInfo unpack_method = lookupUnpackMethod(mt); il.EmitLd(obj); il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, unpack_method); il.EmitStMember(minfo); il.Emit(OpCodes.Br, switchCaseEndLabel); } il.MarkLabel(switchCaseEndLabel); // i ++ il.EmitLd(loop_idx); il.EmitLdc(1); il.Emit(OpCodes.Add); il.EmitSt(loop_idx); // i < num_of_fields; il.MarkLabel(lblLoopExpr); il.EmitLd(loop_idx); il.EmitLd(num_of_fields); il.Emit(OpCodes.Blt, lblLoopStart); // return il.EmitLd(obj); il.Emit(OpCodes.Ret); } static void EmitUnpackArrayCode(Type arrayType, MethodInfo mi, ILGenerator il, Func<Type, MemberInfo[]> targetMemberSelector, Func<MemberInfo, string> memberNameFormatter, Func<Type, MethodInfo> lookupUnpackMethod) { Type elementType = arrayType.GetElementType(); MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); Variable msgpackReader = Variable.CreateArg(0); Variable obj = Variable.CreateLocal(il.DeclareLocal(arrayType)); Variable num_of_elements = Variable.CreateLocal(il.DeclareLocal(typeof(int))); Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int))); Variable type = Variable.CreateLocal(il.DeclareLocal(typeof(Type))); // if (!MsgPackReader.Read() || !MsgPackReader.IsArray ()) UnpackFailed (); EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsArray"), failedMethod, true); // type = typeof (T) il.Emit(OpCodes.Ldtoken, elementType); il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); il.EmitSt(type); // num_of_elements = (int)reader.Length il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod()); il.EmitSt(num_of_elements); // object o = Array.CreateInstance (Type, Length); il.EmitLd(type); il.EmitLd(num_of_elements); il.Emit(OpCodes.Call, typeof(Array).GetMethod("CreateInstance", new Type[] { typeof(Type), typeof(int) })); il.Emit(OpCodes.Castclass, arrayType); il.EmitSt(obj); // Unpack element method MethodInfo unpack_method = lookupUnpackMethod(elementType); // Loop labels Label lblLoopStart = il.DefineLabel(); Label lblLoopExpr = il.DefineLabel(); // i = 0; il.EmitLdc(0); il.EmitSt(loop_idx); il.Emit(OpCodes.Br, lblLoopExpr); il.MarkLabel(lblLoopStart); /* process */ il.EmitLd(obj, loop_idx); il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, unpack_method); il.Emit(OpCodes.Stelem, elementType); // i ++ il.EmitLd(loop_idx); il.EmitLdc(1); il.Emit(OpCodes.Add); il.EmitSt(loop_idx); // i < num_of_fields; il.MarkLabel(lblLoopExpr); il.EmitLd(loop_idx); il.EmitLd(num_of_elements); il.Emit(OpCodes.Blt, lblLoopStart); // return il.EmitLd(obj); il.Emit(OpCodes.Ret); } static void EmitUnpackReadAndTypeCheckCode(ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn) { Label lblFailed = il.DefineLabel(); Label lblNullReturn = nullCheckAndReturn ? il.DefineLabel() : default(Label); Label lblPassed = il.DefineLabel(); il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("Read")); il.Emit(OpCodes.Brfalse_S, lblFailed); if (nullCheckAndReturn) { il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Type").GetGetMethod()); il.EmitLdc((int)TypePrefixes.Nil); il.Emit(OpCodes.Beq_S, lblNullReturn); } il.EmitLd(msgpackReader); il.Emit(OpCodes.Call, typeCheckMethod); il.Emit(OpCodes.Brtrue_S, lblPassed); il.Emit(OpCodes.Br, lblFailed); if (nullCheckAndReturn) { il.MarkLabel(lblNullReturn); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ret); } il.MarkLabel(lblFailed); il.Emit(OpCodes.Call, failedMethod); il.MarkLabel(lblPassed); } /// <summary>Exception Helper</summary> internal static void UnpackFailed() { throw new FormatException(); } #endregion #region Misc static Type GetMemberType(this MemberInfo mi) { if (mi.MemberType == MemberTypes.Field) return ((FieldInfo)mi).FieldType; if (mi.MemberType == MemberTypes.Property) return ((PropertyInfo)mi).PropertyType; throw new ArgumentException(); } #endregion } } namespace MsgPack.Compiler { // // Copyright 2011 Kazuki Oikawa // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Reflection; using System.Reflection.Emit; public static class EmitExtensions { public static void EmitLd(this ILGenerator il, Variable v) { switch (v.VarType) { case VariableType.Arg: EmitLdarg(il, v); break; case VariableType.Local: EmitLdloc(il, v); break; default: throw new ArgumentException(); } } public static void EmitLd(this ILGenerator il, params Variable[] list) { for (int i = 0; i < list.Length; i++) EmitLd(il, list[i]); } public static void EmitLdarg(this ILGenerator il, Variable v) { if (v.VarType != VariableType.Arg) throw new ArgumentException(); switch (v.Index) { case 0: il.Emit(OpCodes.Ldarg_0); return; case 1: il.Emit(OpCodes.Ldarg_1); return; case 2: il.Emit(OpCodes.Ldarg_2); return; case 3: il.Emit(OpCodes.Ldarg_3); return; } if (v.Index <= byte.MaxValue) { il.Emit(OpCodes.Ldarg_S, (byte)v.Index); } else if (v.Index <= short.MaxValue) { il.Emit(OpCodes.Ldarg, v.Index); } else { throw new FormatException(); } } public static void EmitLdloc(this ILGenerator il, Variable v) { if (v.VarType != VariableType.Local) throw new ArgumentException(); switch (v.Index) { case 0: il.Emit(OpCodes.Ldloc_0); return; case 1: il.Emit(OpCodes.Ldloc_1); return; case 2: il.Emit(OpCodes.Ldloc_2); return; case 3: il.Emit(OpCodes.Ldloc_3); return; } if (v.Index <= byte.MaxValue) { il.Emit(OpCodes.Ldloc_S, (byte)v.Index); } else if (v.Index <= short.MaxValue) { il.Emit(OpCodes.Ldloc, v.Index); } else { throw new FormatException(); } } public static void EmitSt(this ILGenerator il, Variable v) { switch (v.VarType) { case VariableType.Arg: EmitStarg(il, v); break; case VariableType.Local: EmitStloc(il, v); break; default: throw new ArgumentException(); } } public static void EmitStarg(this ILGenerator il, Variable v) { if (v.VarType != VariableType.Arg) throw new ArgumentException(); if (v.Index <= byte.MaxValue) { il.Emit(OpCodes.Starg_S, (byte)v.Index); } else if (v.Index <= short.MaxValue) { il.Emit(OpCodes.Starg, v.Index); } else { throw new FormatException(); } } public static void EmitStloc(this ILGenerator il, Variable v) { if (v.VarType != VariableType.Local) throw new ArgumentException(); switch (v.Index) { case 0: il.Emit(OpCodes.Stloc_0); return; case 1: il.Emit(OpCodes.Stloc_1); return; case 2: il.Emit(OpCodes.Stloc_2); return; case 3: il.Emit(OpCodes.Stloc_3); return; } if (v.Index <= byte.MaxValue) { il.Emit(OpCodes.Stloc_S, (byte)v.Index); } else if (v.Index <= short.MaxValue) { il.Emit(OpCodes.Stloc, v.Index); } else { throw new FormatException(); } } public static void EmitLdc(this ILGenerator il, int v) { switch (v) { case 0: il.Emit(OpCodes.Ldc_I4_0); return; case 1: il.Emit(OpCodes.Ldc_I4_1); return; case 2: il.Emit(OpCodes.Ldc_I4_2); return; case 3: il.Emit(OpCodes.Ldc_I4_3); return; case 4: il.Emit(OpCodes.Ldc_I4_4); return; case 5: il.Emit(OpCodes.Ldc_I4_5); return; case 6: il.Emit(OpCodes.Ldc_I4_6); return; case 7: il.Emit(OpCodes.Ldc_I4_7); return; case 8: il.Emit(OpCodes.Ldc_I4_8); return; case -1: il.Emit(OpCodes.Ldc_I4_M1); return; } if (v <= sbyte.MaxValue && v >= sbyte.MinValue) { il.Emit(OpCodes.Ldc_I4_S, (sbyte)v); } else { il.Emit(OpCodes.Ldc_I4, v); } } public static void EmitLd_False(this ILGenerator il) { il.Emit(OpCodes.Ldc_I4_1); } public static void EmitLd_True(this ILGenerator il) { il.Emit(OpCodes.Ldc_I4_1); } public static void EmitLdstr(this ILGenerator il, string v) { il.Emit(OpCodes.Ldstr, v); } public static void EmitLdMember(this ILGenerator il, MemberInfo m) { if (m.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Ldfld, (FieldInfo)m); } else if (m.MemberType == MemberTypes.Property) { il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetGetMethod(true)); } else { throw new ArgumentException(); } } public static void EmitStMember(this ILGenerator il, MemberInfo m) { if (m.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Stfld, (FieldInfo)m); } else if (m.MemberType == MemberTypes.Property) { il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetSetMethod(true)); } else { throw new ArgumentException(); } } } } |