protected override void InnerGenerate(ReaderGenerationContext context) { foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Castclass, type); context.Generator.Emit(OpCodes.Ldarg_0); context.Generator.Emit(OpCodes.Castclass, type); context.Generator.Emit(OpCodes.Ldfld, field); if (!field.FieldType.IsValueType) { var valuesNotEqualLabel = context.Generator.DefineLabel(); context.Generator.Emit(OpCodes.Dup); context.Generator.Emit(OpCodes.Ldarg_0); context.Generator.Emit(OpCodes.Castclass, type); context.Generator.Emit(OpCodes.Bne_Un_S, valuesNotEqualLabel); context.Generator.Emit(OpCodes.Pop); context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Castclass, type); context.Generator.MarkLabel(valuesNotEqualLabel); } context.Generator.Emit(OpCodes.Stfld, field); } }
protected override void InnerGenerate(ReaderGenerationContext context) { var factoryId = objectsForSurrogates.FindMatchingIndex(type); GenerateCallPostDeserializationHooks(context, factoryId); GenerateDesurrogate(context, factoryId); }
private static void GenerateUpdateFields(ReaderGenerationContext context, Type formalType, LocalBuilder objectIdLocal) { var fields = context.DisableStamping ? ((TypeSimpleDescriptor)formalType).FieldsToDeserialize : ((TypeFullDescriptor)formalType).FieldsToDeserialize; foreach (var fieldOrType in fields) { if (fieldOrType.Field == null) { GenerateReadField(context, fieldOrType.TypeToOmit, false); context.Generator.Emit(OpCodes.Pop); continue; } var field = fieldOrType.Field; if (field.IsDefined(typeof(TransientAttribute), false)) { if (field.IsDefined(typeof(ConstructorAttribute), false)) { context.Generator.PushFieldInfoOntoStack(field); context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.GenerateCodeCall <FieldInfo, object>(GenerateUpdateFieldsStaticHelper); } continue; } context.PushDeserializedObjectOntoStack(objectIdLocal); GenerateReadField(context, field.FieldType, false); context.Generator.Emit(OpCodes.Stfld, field); } }
private static void SaveNewDeserializedObject(ReaderGenerationContext context, LocalBuilder objectIdLocal, Action generateNewObject) { context.PushDeserializedObjectsCollectionOntoStack(); context.Generator.PushLocalValueOntoStack(objectIdLocal); generateNewObject(); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <AutoResizingList <object> >(x => x.SetItem(0, null))); }
private static void GenerateReadMethod(ReaderGenerationContext context) { // method returns read methodInfo (or null) context.PushObjectReaderOntoStack(); context.Generator.Emit(OpCodes.Call, Helpers.GetPropertyGetterInfo <ObjectReader, IdentifiedElementsList <MethodDescriptor> >(or => or.Methods)); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <IdentifiedElementsList <MethodDescriptor>, MethodDescriptor>(or => or.Read())); context.Generator.Emit(OpCodes.Call, Helpers.GetPropertyGetterInfo <MethodDescriptor, MethodInfo>(md => md.UnderlyingMethod)); }
internal static void GenerateReadPrimitive(ReaderGenerationContext context, Type type) { context.PushPrimitiveReaderOntoStack(); var mname = string.Concat("Read", type.Name); var readMethod = typeof(PrimitiveReader).GetMethod(mname); if (readMethod == null) { throw new ArgumentException("Method <<" + mname + ">> not found"); } context.Generator.Emit(OpCodes.Call, readMethod); }
protected override MethodInfo GenerateInner() { var dynamicMethod = new DynamicMethod(name, returnType, parameterTypes, typeof(Serializer), true); var generator = dynamicMethod.GetILGenerator(); var context = new ReaderGenerationContext(generator, disableStamping, treatCollectionAsUserObject, objectIdArgument, objectReaderArgument); InnerGenerate(context); context.Generator.Emit(OpCodes.Ret); #if DEBUG_FORMAT GeneratorHelper.DumpToLibrary <T>(context, x => InnerGenerate((ReaderGenerationContext)x), name); #endif return(dynamicMethod); }
private static void GenerateUpdateStructFields(ReaderGenerationContext context, Type formalType, LocalBuilder structLocal) { var fields = context.DisableStamping ? ((TypeSimpleDescriptor)formalType).FieldsToDeserialize : ((TypeFullDescriptor)formalType).FieldsToDeserialize; foreach (var field in fields) { if (field.Field == null) { GenerateReadField(context, field.TypeToOmit, false); context.Generator.Emit(OpCodes.Pop); continue; } if (field.Field.IsDefined(typeof(TransientAttribute), false)) { if (field.Field.IsDefined(typeof(ConstructorAttribute), false)) { context.Generator.PushLocalAddressOntoStack(structLocal); context.Generator.PushFieldInfoOntoStack(field.Field); context.Generator.GenerateCodeFCall <FieldInfo, object>(GenerateUpdateStructFieldsStaticHelper); if (field.Field.FieldType.IsValueType) { context.Generator.Emit(OpCodes.Unbox_Any, field.Field.FieldType); } context.Generator.Emit(OpCodes.Stfld, field.Field); } continue; } context.Generator.PushLocalAddressOntoStack(structLocal); var type = field.TypeToOmit ?? field.Field.FieldType; GenerateReadField(context, type, false); if (field.Field != null) { context.Generator.Emit(OpCodes.Stfld, field.Field); } else { context.Generator.Emit(OpCodes.Pop); // struct local context.Generator.Emit(OpCodes.Pop); // read value } } }
protected override void InnerGenerate(ReaderGenerationContext context) { context.Generator.Emit(OpCodes.Ldarg_0); context.Generator.Emit(OpCodes.Ldarg_1); var addMethod = type.GetMethod("Add"); if (addMethod.GetParameters().Length == 2) { context.Generator.Emit(OpCodes.Ldarg_2); } context.Generator.Emit(OpCodes.Callvirt, addMethod); if (addMethod.ReturnType != typeof(void)) { context.Generator.Emit(OpCodes.Pop); } }
private void GenerateDesurrogate(ReaderGenerationContext context, int factoryId) { if (factoryId == -1) { return; } var desurrogatedObjectLocal = context.Generator.DeclareLocal(typeof(object)); // obtain surrogate factory context.PushObjectReaderOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectReader, SwapList>(x => x.objectsForSurrogates); context.Generator.PushIntegerOntoStack(factoryId); context.Generator.Call <SwapList>(x => x.GetByIndex(0)); // recreate an object from the surrogate var delegateType = typeof(Func <,>).MakeGenericType(type, typeof(object)); context.Generator.Emit(OpCodes.Castclass, delegateType); context.PushDeserializedObjectOntoStack(context.PushObjectIdOntoStack); context.Generator.Emit(OpCodes.Call, delegateType.GetMethod("Invoke")); context.Generator.StoreLocalValueFromStack(desurrogatedObjectLocal); // clone context context.PushObjectReaderOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectReader, Serializer.ReadMethods>(x => x.readMethods); context.Generator.PushFieldValueOntoStack <Serializer.ReadMethods, DynamicMethodProvider <CloneMethodDelegate> >(x => x.cloneContentMehtodsProvider); context.Generator.PushLocalValueOntoStack(desurrogatedObjectLocal); context.Generator.Call <object>(x => x.GetType()); context.Generator.Call <DynamicMethodProvider <CloneMethodDelegate> >(x => x.GetOrCreate(typeof(void))); context.Generator.PushLocalValueOntoStack(desurrogatedObjectLocal); context.PushDeserializedObjectOntoStack(context.PushObjectIdOntoStack, true); context.Generator.Call <CloneMethodDelegate>(x => x.Invoke(null, null)); //remove object reference from surrogatesWhileReading collection context.PushObjectReaderOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectReader, OneToOneMap <int, object> >(x => x.surrogatesWhileReading); context.PushObjectIdOntoStack(); context.Generator.Call <OneToOneMap <int, object> >(x => x.Remove(0)); }
private static void GenerateUpdateElements(ReaderGenerationContext context, Type formalType, LocalBuilder objectIdLocal) { if (typeof(ISpeciallySerializable).IsAssignableFrom(formalType)) { context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.Emit(OpCodes.Castclass, typeof(ISpeciallySerializable)); context.PushPrimitiveReaderOntoStack(); context.Generator.GenerateCodeCall <ISpeciallySerializable, PrimitiveReader>(ObjectReader.LoadAndVerifySpeciallySerializableAndVerify); return; } CollectionMetaToken collectionToken; if (!CollectionMetaToken.TryGetCollectionMetaToken(formalType, out collectionToken)) { throw new InvalidOperationException(InternalErrorMessage); } GenerateFillCollection(context, collectionToken, formalType, objectIdLocal); }
private static void GenerateTouchObject(ReaderGenerationContext context, Type formalType) { var finish = context.Generator.DefineLabel(); context.PushObjectIdOntoStack(); context.PushDeserializedObjectsCollectionOntoStack(); context.Generator.PushPropertyValueOntoStack <AutoResizingList <object>, int>(x => x.Count); // if (refId < deserializedObjects.Count) return; context.Generator.Emit(OpCodes.Blt, finish); if (CreateObjectGenerator.TryFillBody(context.Generator, formalType, context.TreatCollectionAsUserObject, x => { context.PushObjectReaderOntoStack(); context.PushObjectIdOntoStack(); })) { context.Generator.Call <ObjectReader>(x => x.SetObjectByReferenceId(0, null)); } context.Generator.MarkLabel(finish); }
internal static void GenerateReadNotPrecreated(ReaderGenerationContext context, Type formalType, Action pushObjectIdOntoStackAction) { if (formalType.IsValueType) { context.PushDeserializedObjectsCollectionOntoStack(); pushObjectIdOntoStackAction(); GenerateReadField(context, formalType, true); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <AutoResizingList <object> >(x => x.SetItem(0, null))); } else if (formalType.IsArray) { GenerateReadArray(context, formalType, pushObjectIdOntoStackAction); } else if (typeof(MulticastDelegate).IsAssignableFrom(formalType)) { GenerateReadDelegate(context, formalType, pushObjectIdOntoStackAction); } else { throw new InvalidOperationException(InternalErrorMessage + "GenerateReadNotPrecreated"); } }
private static void GenerateReadDelegate(ReaderGenerationContext context, Type type, Action pushObjectIdOntoStackAction) { var invocationListLengthLocal = context.Generator.DeclareLocal(typeof(int)); var targetLocal = context.Generator.DeclareLocal(typeof(object)); GenerateReadPrimitive(context, typeof(int)); context.Generator.StoreLocalValueFromStack(invocationListLengthLocal); GeneratorHelper.GenerateLoop(context, invocationListLengthLocal, cl => { GenerateReadField(context, typeof(object)); context.Generator.StoreLocalValueFromStack(targetLocal); GenerateReadMethod(context); context.Generator.PushTypeOntoStack(type); context.Generator.PushLocalValueOntoStack(targetLocal); context.PushDeserializedObjectsCollectionOntoStack(); pushObjectIdOntoStackAction(); context.Generator.GenerateCodeCall <MethodInfo, Type, object, AutoResizingList <object>, int>(GenerateReadDelegateStaticHelper); }); }
protected override MethodInfo GenerateInner() { DynamicMethod dynamicMethod; if (type.IsArray) { dynamicMethod = new DynamicMethod("Read", returnType, parameterTypes, true); } else { dynamicMethod = new DynamicMethod("Read", returnType, parameterTypes, type, true); } var generator = dynamicMethod.GetILGenerator(); var context = new ReaderGenerationContext(generator, disableStamping, treatCollectionAsUserObject, OpCodes.Ldarg_2, OpCodes.Ldarg_0); GenerateDynamicCode(context, type); #if DEBUG_FORMAT GeneratorHelper.DumpToLibrary <ReadMethodDelegate>(context, c => GenerateDynamicCode((ReaderGenerationContext)c, type)); #endif return(dynamicMethod); }
private static void GenerateReadObjectInner(ReaderGenerationContext context, Type formalType) { var objectIdLocal = context.Generator.DeclareLocal(typeof(int)); context.PushObjectIdOntoStack(); context.Generator.StoreLocalValueFromStack(objectIdLocal); GenerateTouchObject(context, formalType); switch (ObjectReader.GetCreationWay(formalType, context.TreatCollectionAsUserObject)) { case ObjectReader.CreationWay.Null: GenerateReadNotPrecreated(context, formalType, objectIdLocal); break; case ObjectReader.CreationWay.DefaultCtor: GenerateUpdateElements(context, formalType, objectIdLocal); break; case ObjectReader.CreationWay.Uninitialized: GenerateUpdateFields(context, formalType, objectIdLocal); break; } }
protected override void InnerGenerate(ReaderGenerationContext context) { var finish = context.Generator.DefineLabel(); var createdLocal = context.Generator.DeclareLocal(typeof(object)); context.PushObjectIdOntoStack(); context.PushDeserializedObjectsCollectionOntoStack(); context.Generator.PushPropertyValueOntoStack <AutoResizingList <object>, int>(x => x.Count); context.Generator.Emit(OpCodes.Blt, finish); if (CreateObjectGenerator.TryFillBody(context.Generator, type, treatCollectionAsUserObject)) { context.Generator.StoreLocalValueFromStack(createdLocal); context.PushObjectReaderOntoStack(); context.PushObjectIdOntoStack(); context.Generator.PushLocalValueOntoStack(createdLocal); context.Generator.Call <ObjectReader>(x => x.SetObjectByReferenceId(0, null)); } else if (type.IsArray) { var isMultidimensional = type.GetArrayRank() > 1; var elementFormalType = type.GetElementType(); var rankLocal = context.Generator.DeclareLocal(typeof(int)); var lengthsLocal = isMultidimensional ? context.Generator.DeclareLocal(typeof(int[])) : context.Generator.DeclareLocal(typeof(int)); context.PushObjectReaderOntoStack(); context.PushObjectIdOntoStack(); ReadMethodGenerator.GenerateReadPrimitive(context, typeof(int)); context.Generator.StoreLocalValueFromStack(rankLocal); if (isMultidimensional) { context.Generator.PushLocalValueOntoStack(rankLocal); context.Generator.Emit(OpCodes.Newarr, typeof(int)); context.Generator.StoreLocalValueFromStack(lengthsLocal); // create an array for keeping the lengths of each dimension GeneratorHelper.GenerateLoop(context, rankLocal, i => { context.Generator.PushLocalValueOntoStack(lengthsLocal); context.Generator.PushLocalValueOntoStack(i); ReadMethodGenerator.GenerateReadPrimitive(context, typeof(int)); context.Generator.Emit(OpCodes.Stelem, typeof(int)); // populate the lengths with values read from stream }); } else { ReadMethodGenerator.GenerateReadPrimitive(context, typeof(int)); context.Generator.StoreLocalValueFromStack(lengthsLocal); } context.Generator.PushTypeOntoStack(elementFormalType); context.Generator.PushLocalValueOntoStack(lengthsLocal); if (isMultidimensional) { context.Generator.Call(() => Array.CreateInstance(null, new int[0])); } else { context.Generator.Call(() => Array.CreateInstance(null, 0)); } context.Generator.Call <ObjectReader>(x => x.SetObjectByReferenceId(0, null)); } else if (type == typeof(string)) { context.PushObjectReaderOntoStack(); context.PushObjectIdOntoStack(); ReadMethodGenerator.GenerateReadPrimitive(context, typeof(string)); context.Generator.Call <ObjectReader>(x => x.SetObjectByReferenceId(0, null)); var field = Helpers.GetFieldInfo <ObjectReader, int>(x => x.objectsWrittenInlineCount); context.PushObjectReaderOntoStack(); context.Generator.Emit(OpCodes.Dup); context.Generator.Emit(OpCodes.Ldfld, field); context.Generator.PushIntegerOntoStack(1); context.Generator.Emit(OpCodes.Add); context.Generator.Emit(OpCodes.Stfld, field); } else { ReadMethodGenerator.GenerateReadNotPrecreated(context, type, context.PushObjectIdOntoStack); var field = Helpers.GetFieldInfo <ObjectReader, int>(x => x.objectsWrittenInlineCount); context.PushObjectReaderOntoStack(); context.Generator.Emit(OpCodes.Dup); context.Generator.Emit(OpCodes.Ldfld, field); context.Generator.PushIntegerOntoStack(1); context.Generator.Emit(OpCodes.Add); context.Generator.Emit(OpCodes.Stfld, field); } context.Generator.MarkLabel(finish); }
protected abstract void InnerGenerate(ReaderGenerationContext context);
private void GenerateCallPostDeserializationHooks(ReaderGenerationContext context, int factoryId) { var methods = Helpers.GetMethodsWithAttribute(typeof(PostDeserializationAttribute), type).ToArray(); foreach (var method in methods) { if (!method.IsStatic) { context.PushDeserializedObjectOntoStack(context.PushObjectIdOntoStack); context.Generator.Emit(OpCodes.Castclass, method.ReflectedType); } if (method.IsVirtual) { context.Generator.Emit(OpCodes.Callvirt, method); } else { context.Generator.Emit(OpCodes.Call, method); } } methods = Helpers.GetMethodsWithAttribute(typeof(LatePostDeserializationAttribute), type).ToArray(); if (factoryId != -1 && methods.Length != 0) { throw new InvalidOperationException( string.Format(ObjectReader.LateHookAndSurrogateError, type)); } foreach (var method in methods) { context.PushObjectReaderOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectReader, List <Action> >(x => x.latePostDeserializationHooks); context.Generator.PushTypeOntoStack(typeof(Action)); if (method.IsStatic) { context.Generator.Emit(OpCodes.Ldnull); } else { context.PushDeserializedObjectOntoStack(context.PushObjectIdOntoStack); context.Generator.Emit(OpCodes.Castclass, method.ReflectedType); } context.Generator.Emit(OpCodes.Ldtoken, method); if (method.DeclaringType.IsGenericType) { context.Generator.Emit(OpCodes.Ldtoken, method.DeclaringType); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <object, MethodBase>(x => MethodBase.GetMethodFromHandle(new RuntimeMethodHandle(), new RuntimeTypeHandle()))); } else { context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <object, MethodBase>(x => MethodBase.GetMethodFromHandle(new RuntimeMethodHandle()))); } context.Generator.Emit(OpCodes.Castclass, typeof(MethodInfo)); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <object, Delegate>(x => Delegate.CreateDelegate(null, null, method))); context.Generator.Emit(OpCodes.Castclass, typeof(Action)); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <List <Action> >(x => x.Add(null))); } if (callPostDeserializationCallback) { context.PushObjectReaderOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectReader, Action <object> >(x => x.postDeserializationCallback); context.PushDeserializedObjectOntoStack(context.PushObjectIdOntoStack); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Action <object> >(x => x.Invoke(null))); } }
private static void GenerateReadArray(ReaderGenerationContext context, Type arrayType, Action pushObjectIdOntoStackAction) { var isMultidimensional = arrayType.GetArrayRank() > 1; var elementFormalType = arrayType.GetElementType(); var rankLocal = context.Generator.DeclareLocal(typeof(int)); var lengthsLocal = isMultidimensional ? context.Generator.DeclareLocal(typeof(int[])) : context.Generator.DeclareLocal(typeof(int)); var arrayLocal = context.Generator.DeclareLocal(typeof(Array)); var positionLocal = isMultidimensional ? context.Generator.DeclareLocal(typeof(int[])) : context.Generator.DeclareLocal(typeof(int)); var loopControlLocal = context.Generator.DeclareLocal(typeof(int)); // type is int not bool to reuse array length directly var loopBeginLabel = context.Generator.DefineLabel(); var loopEndLabel = context.Generator.DefineLabel(); var nonZeroLengthLabel = context.Generator.DefineLabel(); context.PushDeserializedObjectOntoStack(pushObjectIdOntoStackAction); context.Generator.Emit(OpCodes.Castclass, typeof(Array)); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(arrayLocal); context.Generator.PushPropertyValueOntoStack <Array, int>(x => x.Rank); context.Generator.StoreLocalValueFromStack(rankLocal); if (isMultidimensional) { context.Generator.Emit(OpCodes.Ldc_I4_1); context.Generator.StoreLocalValueFromStack(loopControlLocal); context.Generator.PushLocalValueOntoStack(rankLocal); context.Generator.Emit(OpCodes.Newarr, typeof(int)); context.Generator.StoreLocalValueFromStack(lengthsLocal); // create an array for keeping the lengths of each dimension GeneratorHelper.GenerateLoop(context, rankLocal, i => { context.Generator.PushLocalValueOntoStack(lengthsLocal); context.Generator.PushLocalValueOntoStack(i); context.Generator.PushLocalValueOntoStack(arrayLocal); context.Generator.PushLocalValueOntoStack(i); context.Generator.Call <Array>(x => x.GetLength(0)); context.Generator.Emit(OpCodes.Dup); context.Generator.Emit(OpCodes.Brtrue, nonZeroLengthLabel); context.Generator.Emit(OpCodes.Ldc_I4_0); context.Generator.StoreLocalValueFromStack(loopControlLocal); context.Generator.MarkLabel(nonZeroLengthLabel); context.Generator.Emit(OpCodes.Stelem, typeof(int)); // populate the lengths with values read from stream }); } else { context.Generator.PushLocalValueOntoStack(arrayLocal); context.Generator.Emit(OpCodes.Ldc_I4_0); context.Generator.Call <Array>(x => x.GetLength(0)); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(lengthsLocal); context.Generator.StoreLocalValueFromStack(loopControlLocal); } if (isMultidimensional) { context.Generator.PushLocalValueOntoStack(rankLocal); context.Generator.Emit(OpCodes.Newarr, typeof(int)); context.Generator.StoreLocalValueFromStack(positionLocal); // create an array for keeping the current position of each dimension } context.Generator.MarkLabel(loopBeginLabel); context.Generator.PushLocalValueOntoStack(loopControlLocal); context.Generator.Emit(OpCodes.Brfalse, loopEndLabel); context.Generator.PushLocalValueOntoStack(arrayLocal); context.Generator.Emit(OpCodes.Castclass, arrayType); if (isMultidimensional) { GenerateReadField(context, elementFormalType); context.Generator.PushLocalValueOntoStack(positionLocal); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(a => a.SetValue(null, new int[0]))); } else { context.Generator.PushLocalValueOntoStack(positionLocal); context.Generator.Emit(OpCodes.Ldelema, elementFormalType); GenerateReadField(context, elementFormalType, false); context.Generator.Emit(OpCodes.Stobj, elementFormalType); } if (isMultidimensional) { context.Generator.PushLocalValueOntoStack(positionLocal); context.Generator.PushLocalValueOntoStack(lengthsLocal); context.Generator.PushLocalValueOntoStack(rankLocal); context.Generator.GenerateCodeFCall <int[], int[], int, bool>(GenerateReadArrayStaticHelper); } else { context.Generator.PushLocalValueOntoStack(positionLocal); context.Generator.Emit(OpCodes.Ldc_I4_1); context.Generator.Emit(OpCodes.Add); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(positionLocal); context.Generator.PushLocalValueOntoStack(lengthsLocal); context.Generator.Emit(OpCodes.Clt); } context.Generator.StoreLocalValueFromStack(loopControlLocal); context.Generator.Emit(OpCodes.Br, loopBeginLabel); context.Generator.MarkLabel(loopEndLabel); }
private static void GenerateDynamicCode(ReaderGenerationContext context, Type typeToGenerate) { GenerateReadObjectInner(context, typeToGenerate); context.Generator.Emit(OpCodes.Ret); }
private static void GenerateReadField(ReaderGenerationContext context, Type formalType, bool boxIfValueType = true) { // method returns read field value on stack if (Helpers.IsTransient(formalType)) { context.Generator.PushTypeOntoStack(formalType); context.Generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <object, object>(x => Helpers.GetDefaultValue(null))); if (formalType.IsValueType && boxIfValueType) { context.Generator.Emit(OpCodes.Box, formalType); } return; //return Helpers.GetDefaultValue(_formalType); } var finishLabel = context.Generator.DefineLabel(); if (!formalType.IsValueType) { var referenceIdLocal = context.Generator.DeclareLocal(typeof(int)); var returnDeserializeObjectLabel = context.Generator.DefineLabel(); context.PushObjectReaderOntoStack(); context.Generator.Call <ObjectReader>(x => x.ReadAndTouchReference()); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(referenceIdLocal); context.Generator.Emit(OpCodes.Ldc_I4, Consts.NullObjectId); context.Generator.Emit(OpCodes.Bne_Un, returnDeserializeObjectLabel); context.Generator.Emit(OpCodes.Ldnull); context.Generator.Emit(OpCodes.Br, finishLabel); context.Generator.MarkLabel(returnDeserializeObjectLabel); context.PushDeserializedObjectOntoStack(referenceIdLocal, true); context.Generator.Emit(OpCodes.Castclass, formalType); context.Generator.MarkLabel(finishLabel); return; } var continueWithNullableLabel = context.Generator.DefineLabel(); var forcedFormalType = formalType; var forcedBoxIfValueType = boxIfValueType; var nullableActualType = Nullable.GetUnderlyingType(formalType); if (nullableActualType != null) { forcedFormalType = nullableActualType; forcedBoxIfValueType = true; GenerateReadPrimitive(context, typeof(bool)); context.Generator.Emit(OpCodes.Brtrue, continueWithNullableLabel); context.Generator.Emit(OpCodes.Ldnull); context.Generator.Emit(OpCodes.Br, finishLabel); context.Generator.MarkLabel(continueWithNullableLabel); } if (forcedFormalType.IsEnum) { var actualType = Enum.GetUnderlyingType(forcedFormalType); context.Generator.PushTypeOntoStack(forcedFormalType); GenerateReadPrimitive(context, actualType); context.Generator.Emit(OpCodes.Call, typeof(Enum).GetMethod("ToObject", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(Type), actualType }, null)); if (!forcedBoxIfValueType) { context.Generator.Emit(OpCodes.Unbox_Any, forcedFormalType); } } else if (Helpers.IsWriteableByPrimitiveWriter(forcedFormalType)) { // value type GenerateReadPrimitive(context, forcedFormalType); if (forcedBoxIfValueType) { context.Generator.Emit(OpCodes.Box, forcedFormalType); } } else { // here we have struct var structLocal = context.Generator.DeclareLocal(forcedFormalType); GenerateUpdateStructFields(context, forcedFormalType, structLocal); context.Generator.PushLocalValueOntoStack(structLocal); if (forcedBoxIfValueType) { context.Generator.Emit(OpCodes.Box, forcedFormalType); } } context.Generator.MarkLabel(finishLabel); // if the value is nullable we must use special initialization of it if (nullableActualType != null) { var nullableLocal = context.Generator.DeclareLocal(formalType); var returnNullNullableLabel = context.Generator.DefineLabel(); var endLabel = context.Generator.DefineLabel(); context.Generator.Emit(OpCodes.Dup); context.Generator.Emit(OpCodes.Brfalse, returnNullNullableLabel); if (forcedBoxIfValueType) { context.Generator.Emit(OpCodes.Unbox_Any, nullableActualType); } context.Generator.Emit(OpCodes.Newobj, formalType.GetConstructor(new[] { nullableActualType })); context.Generator.StoreLocalValueFromStack(nullableLocal); context.Generator.PushLocalValueOntoStack(nullableLocal); if (boxIfValueType) { context.Generator.Emit(OpCodes.Box, formalType); } context.Generator.Emit(OpCodes.Br, endLabel); context.Generator.MarkLabel(returnNullNullableLabel); context.Generator.Emit(OpCodes.Pop); context.Generator.PushLocalAddressOntoStack(nullableLocal); context.Generator.Emit(OpCodes.Initobj, formalType); context.Generator.PushLocalValueOntoStack(nullableLocal); if (boxIfValueType) { context.Generator.Emit(OpCodes.Box, nullableLocal); } context.Generator.MarkLabel(endLabel); } }
private static void GenerateReadNotPrecreated(ReaderGenerationContext context, Type formalType, LocalBuilder objectIdLocal) { GenerateReadNotPrecreated(context, formalType, () => context.Generator.PushLocalValueOntoStack(objectIdLocal)); }
private static void GenerateFillCollection(ReaderGenerationContext context, CollectionMetaToken collectionToken, Type collectionType, LocalBuilder objectIdLocal) { var countLocal = context.Generator.DeclareLocal(typeof(int)); GenerateReadPrimitive(context, typeof(int)); context.Generator.StoreLocalValueFromStack(countLocal); // read collection elements count var addMethod = collectionToken.AddMethod; var elementFormalType = collectionToken.FormalElementType; if (collectionType == typeof(Stack) || (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(Stack <>))) { var tempArrLocal = context.Generator.DeclareLocal(elementFormalType.MakeArrayType()); context.Generator.PushLocalValueOntoStack(countLocal); context.Generator.Emit(OpCodes.Newarr, elementFormalType); context.Generator.StoreLocalValueFromStack(tempArrLocal); // creates temporal array GeneratorHelper.GenerateLoop(context, countLocal, cl => { context.Generator.PushLocalValueOntoStack(tempArrLocal); context.Generator.PushLocalValueOntoStack(cl); GenerateReadField(context, elementFormalType, false); context.Generator.Emit(OpCodes.Stelem, elementFormalType); }); GeneratorHelper.GenerateLoop(context, countLocal, cl => { context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.Emit(OpCodes.Castclass, collectionType); context.Generator.PushLocalValueOntoStack(tempArrLocal); context.Generator.PushLocalValueOntoStack(cl); context.Generator.Emit(OpCodes.Ldelem, elementFormalType); context.Generator.Emit(OpCodes.Callvirt, addMethod); }, true); } else { GeneratorHelper.GenerateLoop(context, countLocal, cl => { context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.Emit(OpCodes.Castclass, collectionType); var currentIdLocal = default(LocalBuilder); var debtDifference = default(LocalBuilder); var valueLocal = default(LocalBuilder); if (collectionToken.IsHashCodeBased) { currentIdLocal = context.Generator.DeclareLocal(typeof(int)); debtDifference = context.Generator.DeclareLocal(typeof(int)); } if (collectionToken.IsDictionary) { valueLocal = context.Generator.DeclareLocal(collectionToken.FormalValueType); } if (collectionToken.IsHashCodeBased) { context.PushObjectReaderOntoStack(); context.Generator.Call <ObjectReader>(or => or.GetNewestObjectId()); context.Generator.StoreLocalValueFromStack(currentIdLocal); context.PushObjectReaderOntoStack(); context.Generator.Call <ObjectReader>(or => or.GetObjectDebt()); context.Generator.StoreLocalValueFromStack(debtDifference); } GenerateReadField(context, collectionToken.IsDictionary ? collectionToken.FormalKeyType : collectionToken.FormalElementType, false); if (collectionToken.IsHashCodeBased) { context.PushObjectReaderOntoStack(); context.Generator.Call <ObjectReader>(or => or.GetObjectDebt()); // Here we have new debt on top of the stack but need to load old one. context.Generator.PushLocalValueOntoStack(debtDifference); context.Generator.Emit(OpCodes.Sub); context.Generator.StoreLocalValueFromStack(debtDifference); } if (collectionToken.IsDictionary) { GenerateReadField(context, collectionToken.FormalValueType, false); } if (collectionToken.IsHashCodeBased) { var deferredAddLabel = context.Generator.DefineLabel(); var exitLabel = context.Generator.DefineLabel(); context.Generator.PushLocalValueOntoStack(debtDifference); context.Generator.Emit(OpCodes.Brtrue, deferredAddLabel); context.Generator.Emit(OpCodes.Callvirt, addMethod); context.Generator.Emit(OpCodes.Br, exitLabel); context.Generator.MarkLabel(deferredAddLabel); if (collectionToken.IsDictionary) { context.Generator.StoreLocalValueFromStack(valueLocal); } context.Generator.Emit(OpCodes.Pop); // Key (or value if not dictionary) context.Generator.Emit(OpCodes.Pop); // Collection (object) context.PushObjectReaderOntoStack(); context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.PushLocalValueOntoStack(currentIdLocal); context.Generator.Emit(OpCodes.Ldc_I4_1); context.Generator.Emit(OpCodes.Add); if (collectionToken.IsDictionary) { context.Generator.PushLocalValueOntoStack(valueLocal); } else { context.Generator.Emit(OpCodes.Ldnull); } context.Generator.Call <ObjectReader>(or => or.AddHashCodeBasedWaitingValue(null, 0, null)); context.Generator.MarkLabel(exitLabel); } else { context.Generator.Emit(OpCodes.Callvirt, addMethod); } if (addMethod.ReturnType != typeof(void)) { context.Generator.Emit(OpCodes.Pop); // remove returned unused value from stack } }); } }