private static void GenerateWriteArray(WriterGenerationContext context, Variable arrayLocal, Type actualType) { var rank = actualType.GetArrayRank(); if (rank != 1) { GenerateWriteMultidimensionalArray(context, arrayLocal, actualType, rank); return; } var elementType = actualType.GetElementType(); var currentElementLocal = context.Generator.DeclareLocal(elementType); var lengthLocal = context.Generator.DeclareLocal(typeof(int)); var currentElementVariable = new Variable(currentElementLocal); context.Generator.PushVariableOntoStack(arrayLocal); context.Generator.Emit(OpCodes.Ldlen); context.Generator.StoreLocalValueFromStack(lengthLocal); GeneratorHelper.GenerateLoop(context, lengthLocal, c => { context.Generator.PushVariableOntoStack(arrayLocal); context.Generator.PushLocalValueOntoStack(c); context.Generator.Emit(OpCodes.Ldelem, elementType); context.Generator.StoreLocalValueFromStack(currentElementLocal); GenerateWriteField(context, currentElementVariable, elementType); }); }
private static void GenerateWriteDelegate(WriterGenerationContext context, Variable valueLocal) { var array = context.Generator.DeclareLocal(typeof(Delegate[])); var loopLength = context.Generator.DeclareLocal(typeof(int)); var element = context.Generator.DeclareLocal(typeof(Delegate)); var delegateTargetLocal = context.Generator.DeclareLocal(typeof(object)); var delegateTargetVariable = new Variable(delegateTargetLocal); context.PushPrimitiveWriterOntoStack(); context.PushObjectWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Call <ObjectWriter>(x => x.GetDelegatesWithNonTransientTargets(null)); context.Generator.Emit(OpCodes.Castclass, typeof(Delegate[])); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(array); // array refrence should be on the top of stack here context.Generator.Emit(OpCodes.Ldlen); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(loopLength); // primitive writer should be on the stack // array length should be on the stack context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); GeneratorHelper.GenerateLoop(context, loopLength, c => { context.Generator.PushLocalValueOntoStack(array); context.Generator.PushLocalValueOntoStack(c); context.Generator.Emit(OpCodes.Ldelem, element.LocalType); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(element); // element reference should be on the stack context.Generator.PushPropertyValueOntoStack <MulticastDelegate, object>(x => x.Target); context.Generator.StoreLocalValueFromStack(delegateTargetLocal); GenerateWriteDeferredReference(context, delegateTargetVariable, typeof(object)); context.PushObjectWriterOntoStack(); context.Generator.PushPropertyValueOntoStack <ObjectWriter, IdentifiedElementsDictionary <MethodDescriptor> >(x => x.Methods); context.Generator.PushLocalValueOntoStack(element); context.Generator.PushPropertyValueOntoStack <MulticastDelegate, MethodInfo>(x => x.Method); context.Generator.Emit(OpCodes.Newobj, Helpers.GetConstructorInfo <MethodDescriptor>(typeof(MethodInfo))); context.Generator.Call <IdentifiedElementsDictionary <MethodDescriptor> >(x => x.TouchAndWriteId(null)); context.Generator.Emit(OpCodes.Pop); }); }
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); }); }
private static void GenerateArrayWriteLoop(WriterGenerationContext context, int currentDimension, int rank, LocalBuilder[] indexLocals, LocalBuilder[] lengthLocals, Variable arrayLocal, Variable currentElementVariable, Type arrayType, Type elementType) { GeneratorHelper.GenerateLoop(context, lengthLocals[currentDimension], indexLocals[currentDimension], () => { if (currentDimension == rank - 1) { context.Generator.PushVariableOntoStack(arrayLocal); for (var i = 0; i < rank; i++) { context.Generator.PushLocalValueOntoStack(indexLocals[i]); } // jeśli to nie zadziała to użyć: context.Generator.Emit(OpCodes.Call, arrayType.GetMethod("Get")); context.Generator.StoreVariableValueFromStack(currentElementVariable); GenerateWriteField(context, currentElementVariable, elementType); } else { GenerateArrayWriteLoop(context, currentDimension + 1, rank, indexLocals, lengthLocals, arrayLocal, currentElementVariable, arrayType, elementType); } }); }
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 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 } }); } }
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); }