public static void GenSerializerCall(CodeGenContext ctx, ILGenerator il, Type type) { // We can call the Serializer method directly for: // - Value types // - Array types // - Sealed types with static Serializer method, as the method will handle null // Other reference types go through the SerializesSwitch 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.GetWriterMethodInfo(type) : ctx.SerializerSwitchMethodInfo; il.EmitCall(OpCodes.Call, method, null); }
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) { 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 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); } }
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); } }
public static void GenSerializerCall(CodeGenContext ctx, ILGenerator il, Type type) { // We can call the Serializer method directly for: // - Value types // - Array types // - Sealed types with static Serializer method, as the method will handle null // Other reference types go through the SerializesSwitch 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.GetWriterMethodInfo(type) : ctx.SerializerSwitchMethodInfo; il.EmitCall(OpCodes.Call, method, null); }
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 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 GenSerializerCall(CodeGenContext ctx, ILGenerator il, Type type) { // We can call the Serializer method directly for: // - Value types // - Array types // - Sealed types with static Serializer method, as the method will handle null // Other reference types go through the SerializesSwitch 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.GetWriterMethodInfo(type) : ctx.SerializerSwitchMethodInfo; #else var method = direct ? ctx.GetWriterMethodInfo(type) : typeof(NetSerializer.Serializer).GetMethod("_SerializerSwitch"); #endif il.EmitCall(OpCodes.Call, method, null); }
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); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, 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); Helpers.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 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); }
public void GenerateWriterMethod(Type obtype, CodeGenContext ctx, ILGenerator il) { var getTypeIDMethodInfo = typeof(Serializer).GetMethod("GetTypeID", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var map = ctx.TypeMap; // arg0: Serializer, arg1: Stream, arg2: object var idLocal = il.DeclareLocal(typeof(ushort)); // get TypeID from object's Type il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Call, getTypeIDMethodInfo); il.Emit(OpCodes.Stloc_S, idLocal); // write typeID il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort))); // +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.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, data.WriterMethodInfo); il.Emit(OpCodes.Ret); } }
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"); il.ThrowException(typeof(Exception)); /* 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); } }
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; td.WriterMethodInfo = Helpers.GenerateDynamicSerializerStub(type); td.ReaderMethodInfo = Helpers.GenerateDynamicDeserializerStub(type); } var ctx = new CodeGenContext(map); /* generate bodies */ foreach (var kvp in map) { var type = kvp.Key; var td = kvp.Value; if (!td.IsGenerated) continue; var writerDm = (DynamicMethod)td.WriterMethodInfo; td.TypeSerializer.GenerateWriterMethod(type, ctx, writerDm.GetILGenerator()); var readerDm = (DynamicMethod)td.ReaderMethodInfo; td.TypeSerializer.GenerateReaderMethod(type, ctx, readerDm.GetILGenerator()); } var writer = (DynamicMethod)ctx.GetWriterMethodInfo(typeof(object)); var reader = (DynamicMethod)ctx.GetReaderMethodInfo(typeof(object)); m_serializerSwitch = (SerializerSwitch)writer.CreateDelegate(typeof(SerializerSwitch)); m_deserializerSwitch = (DeserializerSwitch)reader.CreateDelegate(typeof(DeserializerSwitch)); }