private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, bool root, SerializerPair[] basicMethodPairs, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion) { Compiler.CompilerContext ctx; index = 0; hasInheritance = false; methodPairs = new SerializerPair[_types.Count]; foreach (MetaType metaType in _types) { string writeName = "Write"; if (root) { writeName += "Root"; } #if DEBUG writeName += metaType.Type.Name; #endif MethodContext writeGenCtx; MethodBuilder writeMethod = EmitDefineMethod( type, writeName, MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, MapType(typeof(void)), new[] { new MethodContext.ParameterGenInfo(metaType.Type, "obj", 1), new MethodContext.ParameterGenInfo(MapType(typeof(ProtoWriter)), "dest", 2), }, false, out writeGenCtx); string readName = "Read"; if (root) { readName += "Root"; } #if DEBUG readName += metaType.Type.Name; #endif MethodContext readGenCtx; MethodBuilder readMethod = EmitDefineMethod( type, readName, MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new[] { new MethodContext.ParameterGenInfo(metaType.Type, "obj", 1), new MethodContext.ParameterGenInfo(MapType(typeof(ProtoReader)), "source", 2), }, false, out readGenCtx); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeGenCtx, readGenCtx); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) { hasInheritance = true; } } if (hasInheritance) { Array.Sort(methodPairs); } ilVersion = Compiler.CompilerContext.ILVersion.Net2; if (options.MetaDataVersion == 0x10000) { ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school! } for (index = 0; index < methodPairs.Length; index++) { SerializerPair pair = methodPairs[index]; var ser = root ? pair.Type.RootSerializer : pair.Type.Serializer; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, basicMethodPairs ?? methodPairs, this, ilVersion, assemblyName, pair.Type.Type); ctx.CheckAccessibility(pair.Deserialize.ReturnType); ser.EmitWrite(ctx, ctx.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, basicMethodPairs ?? methodPairs, this, ilVersion, assemblyName, pair.Type.Type); ser.EmitRead(ctx, ctx.InputValue); if (!ser.EmitReadReturnsValue) { ctx.LoadValue(ctx.InputValue); } ctx.Return(); } }
private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, SerializerPair[] rootMethodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il) { Compiler.CompilerContext ctx; // arg0 = this, arg1 = key, arg2=obj, arg3=dest Compiler.CodeLabel[] jumpTable; { var genInfo = Override(type, "Serialize"); il = genInfo.GetILGenerator(); ctx = new Compiler.CompilerContext(genInfo, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); jumpTable = new Compiler.CodeLabel[_types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); var labelNoRoot = ctx.DefineLabel(); il.Emit(OpCodes.Ldarg_S, 4); ctx.BranchIfFalse(labelNoRoot, true); WriteSerializePair(il, ctx, rootMethodPairs[i]); ctx.MarkLabel(labelNoRoot); WriteSerializePair(il, ctx, pair); } } { var genInfo = Override(type, "Deserialize"); il = genInfo.GetILGenerator(); ctx = new Compiler.CompilerContext(genInfo, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); var labelNoRoot = ctx.DefineLabel(); il.Emit(OpCodes.Ldarg_S, 4); ctx.BranchIfFalse(labelNoRoot, true); WriteDeserializePair(assemblyName, type, rootMethodPairs, ilVersion, il, rootMethodPairs[i], i, ctx); ctx.MarkLabel(labelNoRoot); WriteDeserializePair(assemblyName, type, methodPairs, ilVersion, il, pair, i, ctx); } } return(ctx); }
private void WriteGetKeyImpl(TypeBuilder type, bool hasInheritance, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName, out ILGenerator il, out int knownTypesCategory, out FieldBuilder knownTypes, out Type knownTypesLookupType) { var genInfo = Override(type, "GetKeyImpl"); il = genInfo.GetILGenerator(); Compiler.CompilerContext ctx = new Compiler.CompilerContext(genInfo, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true)); if (_types.Count <= KnownTypes_ArrayCutoff) { knownTypesCategory = KnownTypes_Array; knownTypesLookupType = MapType(typeof(System.Type[]), true); } else { #if NO_GENERICS knownTypesLookupType = null; #else knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary <System.Type, int>), false); #endif if (knownTypesLookupType == null) { knownTypesLookupType = MapType(typeof(Hashtable), true); knownTypesCategory = KnownTypes_Hashtable; } else { knownTypesCategory = KnownTypes_Dictionary; } } knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); switch (knownTypesCategory) { case KnownTypes_Array: { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod( "IndexOf", new Type[] { MapType(typeof(object)) }), null); if (hasInheritance) { il.DeclareLocal(MapType(typeof(int))); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) { break; } if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(ctx.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Compiler.CodeLabel[] subtypeLabels = new Compiler.CodeLabel[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); ctx.Switch(subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } ctx.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } } break; case KnownTypes_Dictionary: { LocalBuilder result = il.DeclareLocal(MapType(typeof(int))); Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, result); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null); il.Emit(OpCodes.Brfalse_S, otherwise); il.Emit(OpCodes.Ldloc_S, result); il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, otherwise); #if FX11 il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); #else if (ilVersion == Compiler.CompilerContext.ILVersion.Net1) { il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); } else { il.Emit(OpCodes.Unbox_Any, MapType(typeof(int))); } #endif il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } }
private static MethodContext EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs, RuntimeTypeModel model, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName) { MethodInfo dedicated = methodPairs[i].Deserialize; string name = "_" + i.ToString(); MethodContext methodContext; model.EmitDefineMethod( type, name, MethodAttributes.Static, CallingConventions.Standard, model.MapType(typeof(object)), new[] { new MethodContext.ParameterGenInfo(model.MapType(typeof(object)), "obj", 1), new MethodContext.ParameterGenInfo(model.MapType(typeof(ProtoReader)), "source", 2), }, false, out methodContext); Compiler.CompilerContext ctx = new Compiler.CompilerContext(methodContext, true, false, methodPairs, model, ilVersion, assemblyName, model.MapType(typeof(object))); ctx.LoadValue(ctx.InputValue); Compiler.CodeLabel @null = ctx.DefineLabel(); ctx.BranchIfFalse(@null, true); Type mappedValueType = valueType; ctx.LoadValue(ctx.InputValue); ctx.CastFromObject(mappedValueType); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(mappedValueType); ctx.Return(); ctx.MarkLabel(@null); using (Compiler.Local typedVal = new Compiler.Local(ctx, mappedValueType)) { // create a new valueType ctx.LoadAddress(typedVal, mappedValueType); ctx.EmitCtor(mappedValueType); ctx.LoadValue(typedVal); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(mappedValueType); ctx.Return(); } return(methodContext); }