123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Reflection.Emit;
- using System.Reflection;
- using System.Globalization;
- using System.IO;
- namespace PetaJson
- {
- public static class JsonEmit
- {
- public static void Init()
- {
- Json.SetTypeFormatterResolver(Internal.Emit.MakeFormatter);
- Json.SetTypeIntoParserResolver(Internal.Emit.MakeIntoParser);
- }
- }
- namespace Internal
- {
- static class Emit
- {
- public static Action<IJsonWriter, object> MakeFormatter(Type type)
- {
-
- var ri = ReflectionInfo.GetReflectionInfo(type);
- if (ri == null)
- return null;
-
- var method = new DynamicMethod("dynamic_formatter", null, new Type[] { typeof(IJsonWriter), typeof(object) }, true);
- var il = method.GetILGenerator();
-
- var locTypedObj = il.DeclareLocal(type);
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
- il.Emit(OpCodes.Stloc, locTypedObj);
-
- var locInvariant = il.DeclareLocal(typeof(IFormatProvider));
- il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
- il.Emit(OpCodes.Stloc, locInvariant);
-
- var toStringTypes = new Type[] {
- typeof(int), typeof(uint), typeof(long), typeof(ulong),
- typeof(short), typeof(ushort), typeof(decimal),
- typeof(byte), typeof(sbyte)
- };
-
- var otherSupportedTypes = new Type[] {
- typeof(double), typeof(float), typeof(string), typeof(char), typeof(bool)
- };
-
- if (typeof(IJsonWriting).IsAssignableFrom(type))
- {
- il.Emit(OpCodes.Ldloc, locTypedObj);
- if (type.IsValueType)
- il.Emit(OpCodes.Box, type);
- il.Emit(OpCodes.Castclass, typeof(IJsonWriting));
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWriting", new Type[] { typeof(IJsonWriter) }));
- }
-
- foreach (var m in ri.Members)
- {
-
- var pi = m.Member as PropertyInfo;
- if (pi!=null && pi.GetGetMethod() == null)
- {
- continue;
- }
-
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldstr, m.JsonKey);
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) }));
-
- il.Emit(OpCodes.Ldarg_0);
-
- var memberType = m.MemberType;
-
- if (type.IsValueType)
- {
- il.Emit(OpCodes.Ldloca, locTypedObj);
- }
- else
- {
- il.Emit(OpCodes.Ldloc, locTypedObj);
- }
-
- bool NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
- if (Nullable.GetUnderlyingType(memberType) != null)
- {
- NeedValueAddress = true;
- }
-
- if (pi != null)
- {
-
- if (type.IsValueType)
- il.Emit(OpCodes.Call, pi.GetGetMethod());
- else
- il.Emit(OpCodes.Callvirt, pi.GetGetMethod());
-
- if (NeedValueAddress)
- {
- var locTemp = il.DeclareLocal(memberType);
- il.Emit(OpCodes.Stloc, locTemp);
- il.Emit(OpCodes.Ldloca, locTemp);
- }
- }
-
- var fi = m.Member as FieldInfo;
- if (fi != null)
- {
- if (NeedValueAddress)
- {
- il.Emit(OpCodes.Ldflda, fi);
- }
- else
- {
- il.Emit(OpCodes.Ldfld, fi);
- }
- }
- Label? lblFinished = null;
-
- var typeUnderlying = Nullable.GetUnderlyingType(memberType);
- if (typeUnderlying != null)
- {
-
- il.Emit(OpCodes.Dup);
-
- var lblHasValue = il.DefineLabel();
- lblFinished = il.DefineLabel();
-
- il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod());
- il.Emit(OpCodes.Brtrue, lblHasValue);
-
- il.Emit(OpCodes.Pop);
- il.Emit(OpCodes.Ldstr, "null");
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
- il.Emit(OpCodes.Br_S, lblFinished.Value);
-
- il.MarkLabel(lblHasValue);
- il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod());
-
- memberType = typeUnderlying;
- NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
-
- if (NeedValueAddress)
- {
- var locTemp = il.DeclareLocal(memberType);
- il.Emit(OpCodes.Stloc, locTemp);
- il.Emit(OpCodes.Ldloca, locTemp);
- }
- }
-
- if (toStringTypes.Contains(memberType))
- {
-
- il.Emit(OpCodes.Ldloc, locInvariant);
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(IFormatProvider) }));
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
- }
-
- else if (memberType == typeof(float) || memberType == typeof(double))
- {
- il.Emit(OpCodes.Ldstr, "R");
- il.Emit(OpCodes.Ldloc, locInvariant);
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(string), typeof(IFormatProvider) }));
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
- }
-
- else if (memberType == typeof(string))
- {
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
- }
-
- else if (memberType == typeof(char))
- {
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { }));
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
- }
-
- else if (memberType == typeof(bool))
- {
- var lblTrue = il.DefineLabel();
- var lblCont = il.DefineLabel();
- il.Emit(OpCodes.Brtrue_S, lblTrue);
- il.Emit(OpCodes.Ldstr, "false");
- il.Emit(OpCodes.Br_S, lblCont);
- il.MarkLabel(lblTrue);
- il.Emit(OpCodes.Ldstr, "true");
- il.MarkLabel(lblCont);
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
- }
-
- else
- {
-
- if (memberType.IsValueType)
- {
- il.Emit(OpCodes.Box, memberType);
- }
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) }));
- }
- if (lblFinished.HasValue)
- il.MarkLabel(lblFinished.Value);
- }
-
- if (typeof(IJsonWritten).IsAssignableFrom(type))
- {
- il.Emit(OpCodes.Ldloc, locTypedObj);
- if (type.IsValueType)
- il.Emit(OpCodes.Box, type);
- il.Emit(OpCodes.Castclass, typeof(IJsonWritten));
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Callvirt, typeof(IJsonWritten).GetMethod("OnJsonWritten", new Type[] { typeof(IJsonWriter) }));
- }
-
- il.Emit(OpCodes.Ret);
-
- var impl = (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
-
- return (w, obj) =>
- {
- w.WriteDictionary(() =>
- {
- impl(w, obj);
- });
- };
- }
- public static Action<IJsonReader, object> MakeIntoParser(Type type)
- {
-
- var ri = ReflectionInfo.GetReflectionInfo(type);
- if (ri == null)
- return null;
-
- var setters = new Dictionary<string, Action<IJsonReader, object>>();
-
- var numericTypes = new Type[] {
- typeof(int), typeof(uint), typeof(long), typeof(ulong),
- typeof(short), typeof(ushort), typeof(decimal),
- typeof(byte), typeof(sbyte),
- typeof(double), typeof(float)
- };
-
- foreach (var m in ri.Members)
- {
-
- var pi = m.Member as PropertyInfo;
- var fi = m.Member as FieldInfo;
- if (pi != null && pi.GetSetMethod() == null)
- {
- continue;
- }
- if (pi != null && pi.GetGetMethod() == null && m.KeepInstance)
- {
- continue;
- }
-
- var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
- var il = method.GetILGenerator();
-
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(type.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, type);
- if (m.KeepInstance)
- {
-
- il.Emit(OpCodes.Dup);
- if (pi != null)
- il.Emit(OpCodes.Callvirt, pi.GetGetMethod());
- else
- il.Emit(OpCodes.Ldfld, fi);
- var existingInstance = il.DeclareLocal(m.MemberType);
- var lblExistingInstanceNull = il.DefineLabel();
-
- il.Emit(OpCodes.Dup);
- il.Emit(OpCodes.Stloc, existingInstance);
-
- il.Emit(OpCodes.Ldnull);
- il.Emit(OpCodes.Ceq);
- il.Emit(OpCodes.Brtrue_S, lblExistingInstanceNull);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldloc, existingInstance);
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("ParseInto", new Type[] { typeof(Object) }));
- il.Emit(OpCodes.Pop);
- il.Emit(OpCodes.Ret);
- il.MarkLabel(lblExistingInstanceNull);
- }
- Action<string> callHelper = helperName =>
- {
-
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Call, typeof(Emit).GetMethod(helperName, new Type[] { typeof(IJsonReader) }));
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
- };
- if (m.MemberType == typeof(string))
- {
- callHelper("GetLiteralString");
- }
- else if (m.MemberType == typeof(bool))
- {
- callHelper("GetLiteralBool");
- }
- else if (m.MemberType == typeof(char))
- {
- callHelper("GetLiteralChar");
- }
- else if (numericTypes.Contains(m.MemberType))
- {
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Call, typeof(Emit).GetMethod("GetLiteralNumber", new Type[] { typeof(IJsonReader) }));
-
- il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
- il.Emit(OpCodes.Call, m.MemberType.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) }));
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
- }
- else
- {
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldtoken, m.MemberType);
- il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("Parse", new Type[] { typeof(Type) }));
- il.Emit(m.MemberType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, m.MemberType);
- }
- if (pi != null)
- {
- il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, pi.GetSetMethod());
- }
- if (fi != null)
- {
- il.Emit(OpCodes.Stfld, fi);
- }
- il.Emit(OpCodes.Ret);
-
- setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
- }
-
- bool hasLoading = typeof(IJsonLoading).IsAssignableFrom(type);
- bool hasLoaded = typeof(IJsonLoaded).IsAssignableFrom(type);
- Action<IJsonReader, object> parseInto = (reader, obj) =>
- {
- if (hasLoading)
- {
- ((IJsonLoading)obj).OnJsonLoading(reader);
- }
- var lf = obj as IJsonLoadField;
- reader.ReadDictionary(key =>
- {
- if (lf != null)
- {
- if (lf.OnJsonField(reader, key))
- return;
- }
- Action<IJsonReader, object> setter;
- if (setters.TryGetValue(key, out setter))
- {
- setter(reader, obj);
- }
- });
- if (hasLoaded)
- {
- ((IJsonLoaded)obj).OnJsonLoaded(reader);
- }
- };
-
- RegisterParser(type, parseInto);
-
- return parseInto;
- }
- static void RegisterParser(Type type, Action<IJsonReader, object> parseInto)
- {
-
- var method = new DynamicMethod("dynamic_factory", typeof(object), new Type[] { typeof(IJsonReader), typeof(Action<IJsonReader, object>)}, true);
- var il = method.GetILGenerator();
-
- var locObj = il.DeclareLocal(typeof(object));
- if (type.IsValueType)
- {
-
- var locTempStruct = il.DeclareLocal(type);
- il.Emit(OpCodes.Ldloca, locTempStruct);
- il.Emit(OpCodes.Initobj);
- il.Emit(OpCodes.Ldloc, locTempStruct);
- il.Emit(OpCodes.Box, type);
- }
- else
- {
- il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null));
- }
- il.Emit(OpCodes.Dup);
- il.Emit(OpCodes.Stloc, locObj);
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldloc, locObj);
- il.Emit(OpCodes.Callvirt, typeof(Action<IJsonReader, object>).GetMethod("Invoke"));
- il.Emit(OpCodes.Ret);
- var factory = (Func<IJsonReader, Action<IJsonReader,object>, object>)method.CreateDelegate(typeof(Func<IJsonReader, Action<IJsonReader, object>, object>));
- Json.RegisterParser(type, (reader, type2) =>
- {
- return factory(reader, parseInto);
- });
- }
- public static bool GetLiteralBool(IJsonReader r)
- {
- switch (r.GetLiteralKind())
- {
- case LiteralKind.True:
- return true;
- case LiteralKind.False:
- return false;
- default:
- throw new InvalidDataException("expected a boolean value");
- }
- }
- public static char GetLiteralChar(IJsonReader r)
- {
- if (r.GetLiteralKind() != LiteralKind.String)
- throw new InvalidDataException("expected a single character string literal");
- var str = r.GetLiteralString();
- if (str==null || str.Length!=1)
- throw new InvalidDataException("expected a single character string literal");
- return str[0];
- }
- public static string GetLiteralString(IJsonReader r)
- {
- if (r.GetLiteralKind() != LiteralKind.String)
- throw new InvalidDataException("expected a string literal");
- return r.GetLiteralString();
- }
- public static string GetLiteralNumber(IJsonReader r)
- {
- switch (r.GetLiteralKind())
- {
- case LiteralKind.SignedInteger:
- case LiteralKind.UnsignedInteger:
- case LiteralKind.FloatingPoint:
- return r.GetLiteralString();
- }
- throw new InvalidDataException("expected a numeric literal");
- }
- }
- }
- }
|