public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { var valueType = type.GetGenericArguments()[0]; var noValueLabel = il.DefineLabel(); MethodInfo getHasValue = type.GetProperty("HasValue").GetGetMethod(); MethodInfo getValue = type.GetProperty("Value").GetGetMethod(); var data = ctx.GetTypeDataForCall(valueType); il.Emit(OpCodes.Ldarg_1); // Stream il.Emit(OpCodes.Ldarga_S, 2); // &value il.Emit(OpCodes.Call, getHasValue); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(bool))); il.Emit(OpCodes.Ldarga_S, 2); // &value il.Emit(OpCodes.Call, getHasValue); il.Emit(OpCodes.Brfalse_S, noValueLabel); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); // Serializer il.Emit(OpCodes.Ldarg_1); // Stream il.Emit(OpCodes.Ldarga_S, 2); // &value il.Emit(OpCodes.Call, getValue); // XXX for some reason Tailcall causes huge slowdown, at least with "decimal?" //il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, data.WriterMethodInfo); il.MarkLabel(noValueLabel); il.Emit(OpCodes.Ret); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: Serializer, arg1: Stream, arg2: value var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs var fieldType = field.FieldType; var data = ctx.GetTypeDataForCall(fieldType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 2); else il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Call, data.WriterMethodInfo); } il.Emit(OpCodes.Ret); }
static void GenDeserializerBody(CodeGenContext ctx, Type type, ILGenerator il) { if (type.IsClass) { // instantiate empty class il.Emit(OpCodes.Ldarg_1); var gtfh = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var guo = typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, gtfh); il.Emit(OpCodes.Call, guo); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Stind_Ref); } var fields = GetFieldInfos(type); foreach (var field in fields) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (type.IsClass) il.Emit(OpCodes.Ldind_Ref); il.Emit(OpCodes.Ldflda, field); GenDeserializerCall(ctx, il, field.FieldType); } il.Emit(OpCodes.Ret); }
public static void GenerateDeserializerBody(CodeGenContext ctx, Type type, ILGenerator il) { // arg0: stream, arg1: out value if (type.IsArray) GenDeserializerBodyForArray(ctx, type, il); else GenDeserializerBody(ctx, type, il); }
static void GenerateSerializerBody(CodeGenContext ctx, Type type, ILGenerator il) { // arg0: Stream, arg1: value D(il, "ser {0}", type.Name); if (type.IsArray) GenSerializerBodyForArray(ctx, type, il); else GenSerializerBody(ctx, type, il); }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: Serializer, arg1: stream, arg2: out value if (type.IsClass) { // instantiate empty class il.Emit(OpCodes.Ldarg_2); var gtfh = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var guo = typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, gtfh); il.Emit(OpCodes.Call, guo); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Stind_Ref); } var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { var fieldType = field.FieldType; var data = ctx.GetTypeDataForCall(fieldType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); if (type.IsClass) il.Emit(OpCodes.Ldind_Ref); il.Emit(OpCodes.Ldflda, field); il.Emit(OpCodes.Call, data.ReaderMethodInfo); } if (typeof(System.Runtime.Serialization.IDeserializationCallback).IsAssignableFrom(type)) { var miOnDeserialization = typeof(System.Runtime.Serialization.IDeserializationCallback).GetMethod("OnDeserialization", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(Object) }, null); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Constrained, type); il.Emit(OpCodes.Callvirt, miOnDeserialization); } il.Emit(OpCodes.Ret); }
public static void GenerateSerializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary<Type, TypeData> map) { // arg0: Stream, arg1: object var idLocal = il.DeclareLocal(typeof(ushort)); // get TypeID from object's Type var getTypeIDMethod = typeof(Serializer).GetMethod("GetTypeID", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(object) }, null); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getTypeIDMethod, null); il.Emit(OpCodes.Stloc_S, idLocal); // write typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.TypeID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); ConstructorInfo exceptionCtor = typeof(Exception).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); il.Emit(OpCodes.Newobj, exceptionCtor); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); il.EmitCall(OpCodes.Call, data.WriterMethodInfo, null); il.Emit(OpCodes.Ret); } }
static void GenSerializerBody(CodeGenContext ctx, Type type, ILGenerator il) { var fields = GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs il.Emit(OpCodes.Ldarg_0); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 1); else il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, field); GenSerializerCall(ctx, il, field.FieldType); } il.Emit(OpCodes.Ret); }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { var valueType = type.GetGenericArguments()[0]; var hasValueLocal = il.DeclareLocal(typeof(bool)); var valueLocal = il.DeclareLocal(valueType); var notNullLabel = il.DefineLabel(); var data = ctx.GetTypeDataForCall(valueType); // read array len il.Emit(OpCodes.Ldarg_1); // Stream il.Emit(OpCodes.Ldloca_S, hasValueLocal); // &hasValue il.Emit(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(bool))); // if hasValue == 0, return null il.Emit(OpCodes.Ldloc_S, hasValueLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_2); // &value il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Ret); // hasValue == 1 il.MarkLabel(notNullLabel); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); // Serializer il.Emit(OpCodes.Ldarg_1); // Stream il.Emit(OpCodes.Ldloca_S, valueLocal); il.Emit(OpCodes.Call, data.ReaderMethodInfo); il.Emit(OpCodes.Ldarg_2); // &value il.Emit(OpCodes.Ldloc_S, valueLocal); var constr = type.GetConstructor(new[] { valueType }); il.Emit(OpCodes.Newobj, constr); // new Nullable<T>(valueLocal) il.Emit(OpCodes.Stobj, type); // store to &value il.Emit(OpCodes.Ret); }
public static void GenDeserializerCall(CodeGenContext ctx, ILGenerator il, Type type) { // We can call the Deserializer method directly for: // - Value types // - Array types // - Sealed types with static Deserializer method, as the method will handle null // Other reference types go through the DeserializesSwitch bool direct; if (type.IsValueType || type.IsArray) direct = true; else if (type.IsSealed && ctx.IsGenerated(type) == false) direct = true; else direct = false; var method = direct ? ctx.GetReaderMethodInfo(type) : ctx.DeserializerSwitchMethodInfo; il.EmitCall(OpCodes.Call, method, null); }
static void GenSerializerBody(CodeGenContext ctx, Type type, ILGenerator il) { if (type.IsClass) { Type objStackType = typeof(ObjectList); MethodInfo getAddMethod = objStackType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var endLabel = il.DefineLabel(); //==if(objList==null) goto endLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, endLabel); //== objList.Add(value); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getAddMethod, null); il.MarkLabel(endLabel); } var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs il.Emit(OpCodes.Ldarg_0); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 1); else il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ldarg_2); GenSerializerCall(ctx, il, field.FieldType); } il.Emit(OpCodes.Ret); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: Stream, arg1: value var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs il.Emit(OpCodes.Ldarg_0); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 1); else il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, field); Helpers.GenSerializerCall(ctx, il, field.FieldType); } il.Emit(OpCodes.Ret); }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var lenLocal = il.DeclareLocal(typeof(uint)); // read array len il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, lenLocal); il.Emit(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(uint))); var notNullLabel = il.DefineLabel(); /* if len == 0, return null */ il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); var arrLocal = il.DeclareLocal(type); // create new array with len - 1 il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Newarr, elemType); il.Emit(OpCodes.Stloc_S, arrLocal); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // read element to arr[i] var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelema, elemType); il.Emit(OpCodes.Call, data.ReaderMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Blt_S, loopBodyLabel); // store new array to the out value il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brtrue_S, notNullLabel); // if value == null, write 0 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); // write array len + 1 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); // write element at index i il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelem, elemType); il.Emit(OpCodes.Call, data.WriterMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Blt_S, loopBodyLabel); il.Emit(OpCodes.Ret); }
static void GenerateDeserializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary<Type, TypeData> map) { // arg0: stream, arg1: out object D(il, "deser switch"); var idLocal = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.TypeID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); D(il, "eihx"); //il.ThrowException(typeof(Exception)); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); var local = il.DeclareLocal(type); // call deserializer for this typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, local); if (data.WriterMethodInfo.IsGenericMethodDefinition) { Debug.Assert(type.IsGenericType); var genArgs = type.GetGenericArguments(); il.EmitCall(OpCodes.Call, data.ReaderMethodInfo.MakeGenericMethod(genArgs), null); } else { il.EmitCall(OpCodes.Call, data.ReaderMethodInfo, null); } // write result object to out object il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, local); if (type.IsValueType) il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Stind_Ref); D(il, "deser switch done"); il.Emit(OpCodes.Ret); } }
static void GenDeserializerBody(CodeGenContext ctx, Type type, ILGenerator il) { if (type.IsClass) { // instantiate empty class il.Emit(OpCodes.Ldarg_1); var gtfh = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var guo = typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, gtfh); il.Emit(OpCodes.Call, guo); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Stind_Ref); Type objStackType = typeof(ObjectList); MethodInfo getAddMethod = objStackType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var endLabel = il.DefineLabel(); //==if(objList==null) goto endLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, endLabel); //== objList.Add(value); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getAddMethod, null); il.MarkLabel(endLabel); } var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (type.IsClass) il.Emit(OpCodes.Ldind_Ref); il.Emit(OpCodes.Ldflda, field); il.Emit(OpCodes.Ldarg_2); GenDeserializerCall(ctx, il, field.FieldType); } if (typeof(IDeserializationCallback).IsAssignableFrom(type)) { var miOnDeserialization = typeof(IDeserializationCallback).GetMethod("OnDeserialization", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(Object) }, null); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Constrained, type); il.Emit(OpCodes.Callvirt, miOnDeserialization); } il.Emit(OpCodes.Ret); }
static void GenSerializerBodyForArray(CodeGenContext ctx, Type type, ILGenerator il) { var elemType = type.GetElementType(); var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Brtrue_S, notNullLabel); // if value == null, write 0 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4_0); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint)), null); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); // write array len + 1 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint)), null); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // write element at index i il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelem, elemType); GenSerializerCall(ctx, il, elemType); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); il.Emit(OpCodes.Ret); }
public static void GenerateSerializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary<Type, TypeData> map) { // arg0: Stream, arg1: object, arg2: objList //================ Type objStackType = typeof(ObjectList); Type objRefType = typeof(NetSerializer.ObjectRef); MethodInfo getIndexOfMethod = objStackType.GetMethod("IndexOf", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var endLabel = il.DefineLabel(); //==if(objList==null) goto endLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, endLabel); var id = il.DeclareLocal(typeof(int)); //int id = list.IdentityIndexOf(value); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getIndexOfMethod, null); il.Emit(OpCodes.Stloc_S, id); //if (id == -1) goto endLabel; il.Emit(OpCodes.Ldloc_S, id); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Beq, endLabel); //== value = new ObjectRef(id); ConstructorInfo obj_ref_const = objRefType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(int) }, null); il.Emit(OpCodes.Ldloc_S, id); il.Emit(OpCodes.Newobj, obj_ref_const); il.Emit(OpCodes.Box, typeof(ObjectRef)); il.Emit(OpCodes.Starg, 1); il.MarkLabel(endLabel); //=============== var idLocal_typeID = il.DeclareLocal(typeof(uint)); // get TypeID from object's Type var getTypeIDcaseIDMethod = typeof(Serializer).GetMethod("GetTypeIDcaseID", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(object) }, null); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getTypeIDcaseIDMethod, null); il.Emit(OpCodes.Stloc_S, idLocal_typeID); // write typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_S, idLocal_typeID); il.Emit(OpCodes.Ldc_I4, 0xFFFF); il.Emit(OpCodes.And); il.Emit(OpCodes.Conv_U2); il.Emit(OpCodes.Ldarg_2); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.CaseID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal_typeID); il.Emit(OpCodes.Ldc_I4, 16); il.Emit(OpCodes.Shr_Un); il.Emit(OpCodes.Ldc_I4, 0xFFFF); il.Emit(OpCodes.And); il.Emit(OpCodes.Conv_U2); il.Emit(OpCodes.Switch, jumpTable); //-- D(il, "eihx"); ConstructorInfo exceptionCtor = typeof(Exception).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); il.Emit(OpCodes.Newobj, exceptionCtor); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.CaseID]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); il.Emit(OpCodes.Ldarg_2); if (data.WriterMethodInfo.IsGenericMethodDefinition) { Debug.Assert(type.IsGenericType); var genArgs = type.GetGenericArguments(); il.EmitCall(OpCodes.Call, data.WriterMethodInfo.MakeGenericMethod(genArgs), null); } else { il.EmitCall(OpCodes.Call, data.WriterMethodInfo, null); } il.Emit(OpCodes.Ret); } }
static void GenDeserializerCall(CodeGenContext ctx, ILGenerator il, Type type) { // We can call the Deserializer method directly for: // - Value types // - Array types // - Sealed types with static Deserializer method, as the method will handle null // Other reference types go through the DeserializesSwitch bool direct; if (type.IsValueType || type.IsArray) direct = true; else if (type.IsSealed && ctx.IsDynamic(type) == false) direct = true; else direct = false; #if GENERATE_SWITCH var method = direct ? ctx.GetReaderMethodInfo(type) : ctx.DeserializerSwitchMethodInfo; #else var method = direct ? ctx.GetReaderMethodInfo(type) : typeof(NetSerializer.Serializer).GetMethod("_DeserializerSwitch"); #endif il.EmitCall(OpCodes.Call, method, null); }
static Dictionary <Type, ushort> GenerateDynamic(Type[] types) { Dictionary <Type, TypeData> map = GenerateTypeData(types); var nonStaticTypes = map.Where(kvp => kvp.Value.IsDynamic).Select(kvp => kvp.Key); /* generate stubs */ foreach (var type in nonStaticTypes) { var dm = SerializerCodegen.GenerateDynamicSerializerStub(type); map[type].WriterMethodInfo = dm; map[type].WriterILGen = dm.GetILGenerator(); } foreach (var type in nonStaticTypes) { var dm = DeserializerCodegen.GenerateDynamicDeserializerStub(type); map[type].ReaderMethodInfo = dm; map[type].ReaderILGen = dm.GetILGenerator(); } var serializerSwitchMethod = new DynamicMethod("SerializerSwitch", null, new Type[] { typeof(Stream), typeof(object) }, typeof(Serializer), true); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = new DynamicMethod("DeserializerSwitch", null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }, typeof(Serializer), true); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var type in nonStaticTypes) { SerializerCodegen.GenerateSerializerBody(ctx, type, map[type].WriterILGen); } foreach (var type in nonStaticTypes) { DeserializerCodegen.GenerateDeserializerBody(ctx, type, map[type].ReaderILGen); } var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); s_serializerSwitch = (SerializerSwitch)serializerSwitchMethod.CreateDelegate(typeof(SerializerSwitch)); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); s_deserializerSwitch = (DeserializerSwitch)deserializerSwitchMethod.CreateDelegate(typeof(DeserializerSwitch)); return(map.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.TypeID)); }
static void GenSerializerBodyForArray(CodeGenContext ctx, Type type, ILGenerator il) { var elemType = type.GetElementType(); var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Brtrue_S, notNullLabel); // if value == null, write 0 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ldarg_2); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint)), null); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); //============== Type objStackType = typeof(ObjectList); MethodInfo getAddMethod = objStackType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var endLabel = il.DefineLabel(); //==if(objList==null) goto endLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, endLabel); //== objList.Add(value); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getAddMethod, null); il.MarkLabel(endLabel); //============== // write array len + 1 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Ldarg_2); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint)), null); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // write element at index i il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelem, elemType); il.Emit(OpCodes.Ldarg_2); GenSerializerCall(ctx, il, elemType); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); il.Emit(OpCodes.Ret); }
static void GenerateDebugAssembly(Dictionary <Type, TypeData> map) { var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("NetSerializerDebug"), AssemblyBuilderAccess.RunAndSave); var modb = ab.DefineDynamicModule("NetSerializerDebug.dll"); var tb = modb.DefineType("NetSerializer", TypeAttributes.Public); /* generate stubs */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) { continue; } var mb = SerializerCodegen.GenerateStaticSerializerStub(tb, type); td.WriterMethodInfo = mb; td.WriterILGen = mb.GetILGenerator(); var dm = DeserializerCodegen.GenerateStaticDeserializerStub(tb, type); td.ReaderMethodInfo = dm; td.ReaderILGen = dm.GetILGenerator(); } var serializerSwitchMethod = tb.DefineMethod("SerializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object) }); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = tb.DefineMethod("DeserializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) { continue; } td.TypeSerializer.GenerateWriterMethod(type, ctx, td.WriterILGen); td.TypeSerializer.GenerateReaderMethod(type, ctx, td.ReaderILGen); } var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); tb.CreateType(); ab.Save("NetSerializerDebug.dll"); }
static void GenerateDynamic(Dictionary <Type, TypeData> map) { /* generate stubs */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) { continue; } var writerDm = SerializerCodegen.GenerateDynamicSerializerStub(type); td.WriterMethodInfo = writerDm; td.WriterILGen = writerDm.GetILGenerator(); var readerDm = DeserializerCodegen.GenerateDynamicDeserializerStub(type); td.ReaderMethodInfo = readerDm; td.ReaderILGen = readerDm.GetILGenerator(); } var serializerSwitchMethod = new DynamicMethod("SerializerSwitch", null, new Type[] { typeof(Stream), typeof(object) }, typeof(Serializer), true); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = new DynamicMethod("DeserializerSwitch", null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }, typeof(Serializer), true); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) { continue; } td.TypeSerializer.GenerateWriterMethod(type, ctx, td.WriterILGen); td.TypeSerializer.GenerateReaderMethod(type, ctx, td.ReaderILGen); } var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); s_serializerSwitch = (SerializerSwitch)serializerSwitchMethod.CreateDelegate(typeof(SerializerSwitch)); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); s_deserializerSwitch = (DeserializerSwitch)deserializerSwitchMethod.CreateDelegate(typeof(DeserializerSwitch)); }
public static void GenerateDeserializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary <Type, TypeData> map) { // arg0: stream, arg1: out object var idLocal = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) { jumpTable[kvp.Value.TypeID] = il.DefineLabel(); } il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); il.Emit(OpCodes.Newobj, Helpers.ExceptionCtorInfo); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); var local = il.DeclareLocal(type); // call deserializer for this typeID il.Emit(OpCodes.Ldarg_0); if (local.LocalIndex < 256) { il.Emit(OpCodes.Ldloca_S, local); } else { il.Emit(OpCodes.Ldloca, local); } il.EmitCall(OpCodes.Call, data.ReaderMethodInfo, null); // write result object to out object il.Emit(OpCodes.Ldarg_1); if (local.LocalIndex < 256) { il.Emit(OpCodes.Ldloc_S, local); } else { il.Emit(OpCodes.Ldloc, local); } if (type.IsValueType) { il.Emit(OpCodes.Box, type); } il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); } }
public static void GenerateDeserializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary<Type, TypeData> map) { // arg0: stream, arg1: out object var idLocal = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.TypeID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); ConstructorInfo exceptionCtor = typeof(Exception).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); il.Emit(OpCodes.Newobj, exceptionCtor); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); var local = il.DeclareLocal(type); // call deserializer for this typeID il.Emit(OpCodes.Ldarg_0); if (local.LocalIndex < 256) il.Emit(OpCodes.Ldloca_S, local); else il.Emit(OpCodes.Ldloca, local); il.EmitCall(OpCodes.Call, data.ReaderMethodInfo, null); // write result object to out object il.Emit(OpCodes.Ldarg_1); if (local.LocalIndex < 256) il.Emit(OpCodes.Ldloc_S, local); else il.Emit(OpCodes.Ldloc, local); if (type.IsValueType) il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); } }
static void GenerateAssembly(Type[] types) { Dictionary<Type, TypeData> map = GenerateTypeData(types); var nonStaticTypes = map.Where(kvp => kvp.Value.IsDynamic).Select(kvp => kvp.Key); var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("NetSerializerDebug"), AssemblyBuilderAccess.RunAndSave); var modb = ab.DefineDynamicModule("NetSerializerDebug.dll"); var tb = modb.DefineType("NetSerializer", TypeAttributes.Public); /* generate stubs */ foreach (var type in nonStaticTypes) { var mb = GenerateStaticSerializerStub(tb, type); map[type].WriterMethodInfo = mb; map[type].WriterILGen = mb.GetILGenerator(); } foreach (var type in nonStaticTypes) { var dm = GenerateStaticDeserializerStub(tb, type); map[type].ReaderMethodInfo = dm; map[type].ReaderILGen = dm.GetILGenerator(); } var serializerSwitchMethod = tb.DefineMethod("SerializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object) }); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = tb.DefineMethod("DeserializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var type in nonStaticTypes) GenerateSerializerBody(ctx, type, map[type].WriterILGen); foreach (var type in nonStaticTypes) GenerateDeserializerBody(ctx, type, map[type].ReaderILGen); var ilGen = serializerSwitchMethod.GetILGenerator(); GenerateSerializerSwitch(ctx, ilGen, map); ilGen = deserializerSwitchMethod.GetILGenerator(); GenerateDeserializerSwitch(ctx, ilGen, map); tb.CreateType(); ab.Save("NetSerializerDebug.dll"); }
static void GenDeserializerBodyForArray(CodeGenContext ctx, Type type, ILGenerator il) { var elemType = type.GetElementType(); var lenLocal = il.DeclareLocal(typeof(uint)); // read array len il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, lenLocal); il.Emit(OpCodes.Ldarg_2); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(uint)), null); var notNullLabel = il.DefineLabel(); var dataLabel = il.DefineLabel(); var refLabel = il.DefineLabel(); /* if len == 0, return null */ il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); var arrLocal = il.DeclareLocal(type); // create new array with len - 1 il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Newarr, elemType); il.Emit(OpCodes.Stloc_S, arrLocal); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // read element to arr[i] il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelema, elemType); il.Emit(OpCodes.Ldarg_2); GenDeserializerCall(ctx, il, elemType); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); // store new array to the out value il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Stind_Ref); Type objStackType = typeof(ObjectList); MethodInfo getAddMethod = objStackType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var endLabel = il.DefineLabel(); //==if(objList==null) goto endLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, endLabel); //== objList.Add(value); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getAddMethod, null); il.MarkLabel(endLabel); il.Emit(OpCodes.Ret); }
static void GenDeserializerBodyForArray(CodeGenContext ctx, Type type, ILGenerator il) { var elemType = type.GetElementType(); var lenLocal = il.DeclareLocal(typeof(uint)); // read array len il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, lenLocal); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(uint)), null); var notNullLabel = il.DefineLabel(); /* if len == 0, return null */ il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); var arrLocal = il.DeclareLocal(type); // create new array with len - 1 il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Newarr, elemType); il.Emit(OpCodes.Stloc_S, arrLocal); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // read element to arr[i] il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelema, elemType); GenDeserializerCall(ctx, il, elemType); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); // store new array to the out value il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); }
public static void GenerateDeserializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary<Type, TypeData> map) { // arg0: stream, arg1: out object, arg2: objList //-- D(il, "deser switch"); var idLocal_typeID = il.DeclareLocal(typeof(ushort)); var idLocal_caseID = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, idLocal_typeID); il.Emit(OpCodes.Ldarg_2); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort)), null); // get CaseID from TypeID var getCaseIDMethod = typeof(Serializer).GetMethod("GetCaseID", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(ushort) }, null); il.Emit(OpCodes.Ldloc_S, idLocal_typeID); il.EmitCall(OpCodes.Call, getCaseIDMethod, null); il.Emit(OpCodes.Stloc_S, idLocal_caseID); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.CaseID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal_caseID); il.Emit(OpCodes.Switch, jumpTable); //-- D(il, "eihx"); ConstructorInfo exceptionCtor = typeof(Exception).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); il.Emit(OpCodes.Newobj, exceptionCtor); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.CaseID]); var local = il.DeclareLocal(type); // call deserializer for this typeID il.Emit(OpCodes.Ldarg_0); if (local.LocalIndex < 256) il.Emit(OpCodes.Ldloca_S, local); else il.Emit(OpCodes.Ldloca, local); il.Emit(OpCodes.Ldarg_2); if (data.WriterMethodInfo.IsGenericMethodDefinition) { Debug.Assert(type.IsGenericType); var genArgs = type.GetGenericArguments(); il.EmitCall(OpCodes.Call, data.ReaderMethodInfo.MakeGenericMethod(genArgs), null); } else { il.EmitCall(OpCodes.Call, data.ReaderMethodInfo, null); } if (type == typeof(ObjectRef)) { // get Object by Ref and write found object to out object var getGetAt = typeof(ObjectList).GetMethod("GetAt", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ObjectRef) }, null); var nullLabel = il.DefineLabel(); //==if(objList==null) goto nullLabel; il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brfalse_S, nullLabel); //== value = objList.GetAt(obj.obj_ref); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, local); il.EmitCall(OpCodes.Call, getGetAt, null); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(nullLabel); //== value = null; il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); } else { // write result object to out object il.Emit(OpCodes.Ldarg_1); if (local.LocalIndex < 256) il.Emit(OpCodes.Ldloc_S, local); else il.Emit(OpCodes.Ldloc, local); if (type.IsValueType) il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Stind_Ref); } //-- D(il, "deser switch done"); il.Emit(OpCodes.Ret); } }
static void GenerateDebugAssembly(Dictionary<Type, TypeData> map) { var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("NetSerializerDebug"), AssemblyBuilderAccess.RunAndSave); var modb = ab.DefineDynamicModule("NetSerializerDebug.dll"); var tb = modb.DefineType("NetSerializer", TypeAttributes.Public); /* generate stubs */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) continue; var mb = SerializerCodegen.GenerateStaticSerializerStub(tb, type); td.WriterMethodInfo = mb; td.WriterILGen = mb.GetILGenerator(); var dm = DeserializerCodegen.GenerateStaticDeserializerStub(tb, type); td.ReaderMethodInfo = dm; td.ReaderILGen = dm.GetILGenerator(); } var serializerSwitchMethod = tb.DefineMethod("SerializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object) }); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = tb.DefineMethod("DeserializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) continue; td.TypeSerializer.GenerateWriterMethod(type, ctx, td.WriterILGen); td.TypeSerializer.GenerateReaderMethod(type, ctx, td.ReaderILGen); } var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); tb.CreateType(); ab.Save("NetSerializerDebug.dll"); }
static void GenerateSerializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary <Type, TypeData> map) { // arg0: Stream, arg1: object var idLocal = il.DeclareLocal(typeof(ushort)); // get TypeID from object's Type var getTypeIDMethod = typeof(Serializer).GetMethod("GetTypeID", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(object) }, null); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, getTypeIDMethod, null); il.Emit(OpCodes.Stloc_S, idLocal); // write typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) { jumpTable[kvp.Value.TypeID] = il.DefineLabel(); } il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); D(il, "eihx"); ConstructorInfo exceptionCtor = typeof(Exception).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); il.Emit(OpCodes.Newobj, exceptionCtor); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); if (data.WriterMethodInfo.IsGenericMethodDefinition) { Debug.Assert(type.IsGenericType); var genArgs = type.GetGenericArguments(); il.EmitCall(OpCodes.Call, data.WriterMethodInfo.MakeGenericMethod(genArgs), null); } else { il.EmitCall(OpCodes.Call, data.WriterMethodInfo, null); } il.Emit(OpCodes.Ret); } }
static Dictionary<Type, TypeData> GenerateDynamic(Type[] types, Dictionary<Type, TypeData> typeMap) { Dictionary<Type, TypeData> _map = GenerateTypeData(types); Dictionary<Type, TypeData> map = typeMap.Concat(_map).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var nonStaticTypes = map.Where(kvp => kvp.Value.IsDynamic).Select(kvp => kvp.Key); /* generate stubs */ foreach (var type in nonStaticTypes) { var s_dm = SerializerCodegen.GenerateDynamicSerializerStub(type); var typeData = map[type]; typeData.WriterMethodInfo = s_dm; typeData.WriterILGen = s_dm.GetILGenerator(); var d_dm = DeserializerCodegen.GenerateDynamicDeserializerStub(type); typeData.ReaderMethodInfo = d_dm; typeData.ReaderILGen = d_dm.GetILGenerator(); } #if GENERATE_SWITCH var serializerSwitchMethod = new DynamicMethod("SerializerSwitch", null, new Type[] { typeof(Stream), typeof(object), typeof(ObjectList) }, typeof(Serializer), true); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); serializerSwitchMethod.DefineParameter(3, ParameterAttributes.None, "objList"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = new DynamicMethod("DeserializerSwitch", null, new Type[] { typeof(Stream), typeof(object).MakeByRefType(), typeof(ObjectList) }, typeof(Serializer), true); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); deserializerSwitchMethod.DefineParameter(3, ParameterAttributes.Out, "objList"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); #else var ctx = new CodeGenContext(map); #endif /* generate bodies */ foreach (var type in nonStaticTypes) { SerializerCodegen.GenerateSerializerBody(ctx, type, map[type].WriterILGen); DeserializerCodegen.GenerateDeserializerBody(ctx, type, map[type].ReaderILGen); } #if GENERATE_SWITCH var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); s_serializerSwitch = (SerializerSwitch)serializerSwitchMethod.CreateDelegate(typeof(SerializerSwitch)); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); s_deserializerSwitch = (DeserializerSwitch)deserializerSwitchMethod.CreateDelegate(typeof(DeserializerSwitch)); #else foreach (var kvp in map) { kvp.Value.serializer = GetSerializationInvoker(null, kvp.Value.WriterMethodInfo, kvp.Key, (int)kvp.Value.TypeID); kvp.Value.deserializer = GetDeserializationInvoker(null, kvp.Value.ReaderMethodInfo, kvp.Key, (int)kvp.Value.TypeID); } #endif return map; }
static void GenerateDeserializerSwitch(CodeGenContext ctx, ILGenerator il, IDictionary <Type, TypeData> map) { // arg0: stream, arg1: out object D(il, "deser switch"); var idLocal = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, idLocal); il.EmitCall(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort)), null); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) { jumpTable[kvp.Value.TypeID] = il.DefineLabel(); } il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); D(il, "eihx"); //il.ThrowException(typeof(Exception)); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); var local = il.DeclareLocal(type); // call deserializer for this typeID il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, local); if (data.WriterMethodInfo.IsGenericMethodDefinition) { Debug.Assert(type.IsGenericType); var genArgs = type.GetGenericArguments(); il.EmitCall(OpCodes.Call, data.ReaderMethodInfo.MakeGenericMethod(genArgs), null); } else { il.EmitCall(OpCodes.Call, data.ReaderMethodInfo, null); } // write result object to out object il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, local); if (type.IsValueType) { il.Emit(OpCodes.Box, type); } il.Emit(OpCodes.Stind_Ref); D(il, "deser switch done"); il.Emit(OpCodes.Ret); } }
static Dictionary<Type, uint> s_Type_caseIDtypeIDMap; // Type => (typeID | (caseID << 16)) #endif #if GENERATE_DEBUGGING_ASSEMBLY static void GenerateAssembly(Type[] types, Dictionary<Type, TypeData> typeMap) { Dictionary<Type, TypeData> _map = GenerateTypeData(types); Dictionary<Type, TypeData> map = typeMap.Concat(_map).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var nonStaticTypes = map.Where(kvp => kvp.Value.IsDynamic).Select(kvp => kvp.Key); var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("NetSerializerDebug"), AssemblyBuilderAccess.RunAndSave); var modb = ab.DefineDynamicModule("NetSerializerDebug.dll"); var tb = modb.DefineType("NetSerializer", TypeAttributes.Public); /* generate stubs */ foreach (var type in nonStaticTypes) { var mb = SerializerCodegen.GenerateStaticSerializerStub(tb, type); map[type].WriterMethodInfo = mb; map[type].WriterILGen = mb.GetILGenerator(); } foreach (var type in nonStaticTypes) { var dm = DeserializerCodegen.GenerateStaticDeserializerStub(tb, type); map[type].ReaderMethodInfo = dm; map[type].ReaderILGen = dm.GetILGenerator(); } #if GENERATE_SWITCH var serializerSwitchMethod = tb.DefineMethod("SerializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object), typeof(ObjectList) }); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); serializerSwitchMethod.DefineParameter(3, ParameterAttributes.None, "objList"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = tb.DefineMethod("DeserializerSwitch", MethodAttributes.Public | MethodAttributes.Static, null, new Type[] { typeof(Stream), typeof(object).MakeByRefType(), typeof(ObjectList) }); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); deserializerSwitchMethod.DefineParameter(3, ParameterAttributes.None, "objList"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); #else var ctx = new CodeGenContext(map); #endif /* generate bodies */ foreach (var type in nonStaticTypes) { SerializerCodegen.GenerateSerializerBody(ctx, type, map[type].WriterILGen); DeserializerCodegen.GenerateDeserializerBody(ctx, type, map[type].ReaderILGen); } #if GENERATE_SWITCH var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); #else foreach (var kvp in map) { GetSerializationInvoker(tb, kvp.Value.WriterMethodInfo, kvp.Key, (int)kvp.Value.TypeID); GetDeserializationInvoker(tb, kvp.Value.ReaderMethodInfo, kvp.Key, (int)kvp.Value.TypeID); } #endif tb.CreateType(); ab.Save("NetSerializerDebug.dll"); SerializationID.userID = SerializationID.userIDstart; }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var lenLocal = il.DeclareLocal(typeof(uint)); // read array len il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, lenLocal); il.Emit(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(uint))); var notNullLabel = il.DefineLabel(); /* if len == 0, return null */ il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); var arrLocal = il.DeclareLocal(type); // create new array with len - 1 il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Newarr, elemType); il.Emit(OpCodes.Stloc_S, arrLocal); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // read element to arr[i] var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelema, elemType); il.Emit(OpCodes.Call, data.ReaderMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Blt_S, loopBodyLabel); // store new array to the out value il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); }
static void GenDeserializerBody(CodeGenContext ctx, Type type, ILGenerator il) { if (type.IsClass) { // instantiate empty class il.Emit(OpCodes.Ldarg_1); var gtfh = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var guo = typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, gtfh); il.Emit(OpCodes.Call, guo); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Stind_Ref); } var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (type.IsClass) il.Emit(OpCodes.Ldind_Ref); il.Emit(OpCodes.Ldflda, field); GenDeserializerCall(ctx, il, field.FieldType); } if (typeof(IDeserializationCallback).IsAssignableFrom(type)) { var miOnDeserialization = typeof(IDeserializationCallback).GetMethod("OnDeserialization", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(Object) }, null); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Constrained, type); il.Emit(OpCodes.Callvirt, miOnDeserialization); } il.Emit(OpCodes.Ret); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brtrue_S, notNullLabel); // if value == null, write 0 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); // write array len + 1 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } // write element at index i il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelem, elemType); il.Emit(OpCodes.Call, data.WriterMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Blt_S, loopBodyLabel); il.Emit(OpCodes.Ret); }
static Dictionary<Type, ushort> GenerateDynamic(Type[] types) { Dictionary<Type, TypeData> map = GenerateTypeData(types); var nonStaticTypes = map.Where(kvp => kvp.Value.IsDynamic).Select(kvp => kvp.Key); /* generate stubs */ foreach (var type in nonStaticTypes) { var dm = GenerateDynamicSerializerStub(type); map[type].WriterMethodInfo = dm; map[type].WriterILGen = dm.GetILGenerator(); } foreach (var type in nonStaticTypes) { var dm = GenerateDynamicDeserializerStub(type); map[type].ReaderMethodInfo = dm; map[type].ReaderILGen = dm.GetILGenerator(); } var serializerSwitchMethod = new DynamicMethod("SerializerSwitch", null, new Type[] { typeof(Stream), typeof(object) }, typeof(Serializer), true); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = new DynamicMethod("DeserializerSwitch", null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }, typeof(Serializer), true); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var type in nonStaticTypes) GenerateSerializerBody(ctx, type, map[type].WriterILGen); foreach (var type in nonStaticTypes) GenerateDeserializerBody(ctx, type, map[type].ReaderILGen); var ilGen = serializerSwitchMethod.GetILGenerator(); GenerateSerializerSwitch(ctx, ilGen, map); s_serializerSwitch = (SerializerSwitch)serializerSwitchMethod.CreateDelegate(typeof(SerializerSwitch)); ilGen = deserializerSwitchMethod.GetILGenerator(); GenerateDeserializerSwitch(ctx, ilGen, map); s_deserializerSwitch = (DeserializerSwitch)deserializerSwitchMethod.CreateDelegate(typeof(DeserializerSwitch)); return map.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.TypeID); }
static void GenerateDynamic(Dictionary<Type, TypeData> map) { /* generate stubs */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) continue; var writerDm = SerializerCodegen.GenerateDynamicSerializerStub(type); td.WriterMethodInfo = writerDm; td.WriterILGen = writerDm.GetILGenerator(); var readerDm = DeserializerCodegen.GenerateDynamicDeserializerStub(type); td.ReaderMethodInfo = readerDm; td.ReaderILGen = readerDm.GetILGenerator(); } var serializerSwitchMethod = new DynamicMethod("SerializerSwitch", null, new Type[] { typeof(Stream), typeof(object) }, typeof(Serializer), true); serializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); serializerSwitchMethod.DefineParameter(2, ParameterAttributes.None, "value"); var serializerSwitchMethodInfo = serializerSwitchMethod; var deserializerSwitchMethod = new DynamicMethod("DeserializerSwitch", null, new Type[] { typeof(Stream), typeof(object).MakeByRefType() }, typeof(Serializer), true); deserializerSwitchMethod.DefineParameter(1, ParameterAttributes.None, "stream"); deserializerSwitchMethod.DefineParameter(2, ParameterAttributes.Out, "value"); var deserializerSwitchMethodInfo = deserializerSwitchMethod; var ctx = new CodeGenContext(map, serializerSwitchMethodInfo, deserializerSwitchMethodInfo); /* generate bodies */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) continue; td.TypeSerializer.GenerateWriterMethod(type, ctx, td.WriterILGen); td.TypeSerializer.GenerateReaderMethod(type, ctx, td.ReaderILGen); } var ilGen = serializerSwitchMethod.GetILGenerator(); SerializerCodegen.GenerateSerializerSwitch(ctx, ilGen, map); s_serializerSwitch = (SerializerSwitch)serializerSwitchMethod.CreateDelegate(typeof(SerializerSwitch)); ilGen = deserializerSwitchMethod.GetILGenerator(); DeserializerCodegen.GenerateDeserializerSwitch(ctx, ilGen, map); s_deserializerSwitch = (DeserializerSwitch)deserializerSwitchMethod.CreateDelegate(typeof(DeserializerSwitch)); }