private static void GenerateFillCollection(ReaderGenerationContext context, Type elementFormalType, 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 = collectionType.GetMethod("Add", new[] { elementFormalType }) ?? collectionType.GetMethod("Enqueue", new[] { elementFormalType }) ?? collectionType.GetMethod("Push", new[] { elementFormalType }); if (addMethod == null) { throw new InvalidOperationException(string.Format(CouldNotFindAddErrorMessage, collectionType)); } 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, collectionType.GetMethod("Push")); }, true); } else { GeneratorHelper.GenerateLoop(context, countLocal, cl => { context.PushDeserializedObjectOntoStack(objectIdLocal); context.Generator.Emit(OpCodes.Castclass, collectionType); GenerateReadField(context, elementFormalType, false); context.Generator.Emit(OpCodes.Callvirt, addMethod); if (addMethod.ReturnType != typeof(void)) { context.Generator.Emit(OpCodes.Pop); // remove returned unused value from stack } }); } }
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>((method, t, target, deserializedObjects, objectId) => { var del = Delegate.CreateDelegate(t, target, method); deserializedObjects[objectId] = Delegate.Combine((Delegate)deserializedObjects[objectId], del); }); }); }
private void GenerateReadReadOnlyCollection(Type type, LocalBuilder objectIdLocal) { var elementFormalType = type.GetGenericArguments()[0]; var lengthLocal = generator.DeclareLocal(typeof(Int32)); var arrayLocal = generator.DeclareLocal(elementFormalType.MakeArrayType()); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Stloc, lengthLocal); // read number of elements in the collection generator.Emit(OpCodes.Ldloc, lengthLocal); generator.Emit(OpCodes.Newarr, elementFormalType); generator.Emit(OpCodes.Stloc, arrayLocal); // create array GeneratorHelper.GenerateLoop(generator, lengthLocal, lc => { generator.Emit(OpCodes.Ldloc, arrayLocal); generator.Emit(OpCodes.Ldloc, lc); GenerateReadField(elementFormalType); generator.Emit(OpCodes.Stelem, elementFormalType); }); SaveNewDeserializedObject(objectIdLocal, () => { generator.Emit(OpCodes.Ldloc, arrayLocal); generator.Emit(OpCodes.Castclass, typeof(IList <>).MakeGenericType(elementFormalType)); generator.Emit(OpCodes.Newobj, type.GetConstructor(new [] { typeof(IList <>).MakeGenericType(elementFormalType) })); }); }
private void GenerateReadDelegate(Type type, LocalBuilder objectIdLocal) { var invocationListLengthLocal = generator.DeclareLocal(typeof(Int32)); var targetLocal = generator.DeclareLocal(typeof(object)); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Stloc, invocationListLengthLocal); GeneratorHelper.GenerateLoop(generator, invocationListLengthLocal, cl => { GenerateReadField(typeof(object)); generator.Emit(OpCodes.Stloc, targetLocal); GenerateReadMethod(); PushTypeOntoStack(type); generator.Emit(OpCodes.Ldloc, targetLocal); PushDeserializedObjectsCollectionOntoStack(); generator.Emit(OpCodes.Ldloc, objectIdLocal); GenerateCodeCall <MethodInfo, Type, object, AutoResizingList <object>, int>((method, t, target, deserializedObjects, objectId) => { var del = Delegate.CreateDelegate(t, target, method); deserializedObjects[objectId] = Delegate.Combine((Delegate)deserializedObjects[objectId], del); }); }); }
private void GenerateFillDictionary(CollectionMetaToken collectionToken, Type dictionaryType, LocalBuilder objectIdLocal) { var countLocal = generator.DeclareLocal(typeof(Int32)); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Stloc, countLocal); // read dictionary elements count var addMethodArgumentTypes = new [] { collectionToken.FormalKeyType, collectionToken.FormalValueType }; var addMethod = dictionaryType.GetMethod("Add", addMethodArgumentTypes) ?? dictionaryType.GetMethod("TryAdd", addMethodArgumentTypes); if (addMethod == null) { throw new InvalidOperationException(string.Format(CouldNotFindAddErrorMessage, dictionaryType)); } GeneratorHelper.GenerateLoop(generator, countLocal, lc => { PushDeserializedObjectOntoStack(objectIdLocal); generator.Emit(OpCodes.Castclass, dictionaryType); GenerateReadField(collectionToken.FormalKeyType, false); GenerateReadField(collectionToken.FormalValueType, false); generator.Emit(OpCodes.Callvirt, addMethod); if (addMethod.ReturnType != typeof(void)) { generator.Emit(OpCodes.Pop); // remove returned unused value from stack } }); }
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); }); }
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 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 void GenerateWriteDelegate(Action <ILGenerator> putValueToWriteOnTop) { var delegateTouchAndWriteMethodId = Helpers.GetMethodInfo <ObjectWriter, MethodInfo>((writer, method) => writer.TouchAndWriteMethodId(method)); var delegateGetInvocationList = Helpers.GetMethodInfo <ObjectWriter, MulticastDelegate>((writer, md) => writer.GetDelegatesWithNonTransientTargets(md)); var delegateGetMethodInfo = typeof(MulticastDelegate).GetProperty("Method").GetGetMethod(); var delegateGetTarget = typeof(MulticastDelegate).GetProperty("Target").GetGetMethod(); var array = generator.DeclareLocal(typeof(Delegate[])); var loopLength = generator.DeclareLocal(typeof(int)); var element = generator.DeclareLocal(typeof(Delegate)); generator.Emit(OpCodes.Ldarg_1); // primitiveWriter generator.Emit(OpCodes.Ldarg_0); // objectWriter putValueToWriteOnTop(generator); // delegate to serialize of type MulticastDelegate generator.Emit(OpCodes.Call, delegateGetInvocationList); generator.Emit(OpCodes.Castclass, typeof(Delegate[])); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Stloc_S, array.LocalIndex); generator.Emit(OpCodes.Ldlen); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Stloc_S, loopLength.LocalIndex); generator.Emit(OpCodes.Call, primitiveWriterWriteInteger); GeneratorHelper.GenerateLoop(generator, loopLength, c => { generator.Emit(OpCodes.Ldloc, array); generator.Emit(OpCodes.Ldloc, c); generator.Emit(OpCodes.Ldelem, element.LocalType); generator.Emit(OpCodes.Stloc, element); GenerateWriteReference(gen => { gen.Emit(OpCodes.Ldloc, element); gen.Emit(OpCodes.Call, delegateGetTarget); }, typeof(object)); generator.Emit(OpCodes.Ldarg_0); // objectWriter generator.Emit(OpCodes.Ldloc, element); generator.Emit(OpCodes.Call, delegateGetMethodInfo); generator.Emit(OpCodes.Call, delegateTouchAndWriteMethodId); generator.Emit(OpCodes.Pop); }); }
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); } }); }
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); }
protected override MethodInfo GenerateInner() { DynamicMethod dynamicMethod = null; if (!type.IsArray) { dynamicMethod = new DynamicMethod(string.Format("Write_{0}", type.Name), returnType, parameterTypes, type, true); } else { var methodNo = Interlocked.Increment(ref WriteArrayMethodCounter); dynamicMethod = new DynamicMethod(string.Format("WriteArray{0}_{1}", methodNo, type.Name), returnType, parameterTypes, true); } var generator = dynamicMethod.GetILGenerator(); var context = new WriterGenerationContext(generator, false, treatCollectionAsUserObject, OpCodes.Ldarg_0); #if DEBUG_FORMAT GeneratorHelper.DumpToLibrary <WriteMethodDelegate>(context, c => GenerateDynamicCode((WriterGenerationContext)c, type), type.Name); #endif GenerateDynamicCode(context, type); return(dynamicMethod); }
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); }
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); }
private void GenerateReadArray(Type elementFormalType, LocalBuilder objectIdLocal) { var rankLocal = generator.DeclareLocal(typeof(Int32)); var lengthsLocal = generator.DeclareLocal(typeof(Int32[])); var arrayLocal = generator.DeclareLocal(typeof(Array)); var positionLocal = generator.DeclareLocal(typeof(Int32[])); var loopControlLocal = generator.DeclareLocal(typeof(bool)); var loopBeginLabel = generator.DefineLabel(); var loopEndLabel = generator.DefineLabel(); var lengthIsZeroLabel = generator.DefineLabel(); var isNotEmptyArrayLocal = generator.DeclareLocal(typeof(bool)); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Stloc, rankLocal); // read amount of dimensions of the array generator.Emit(OpCodes.Ldloc, rankLocal); generator.Emit(OpCodes.Newarr, typeof(Int32)); generator.Emit(OpCodes.Stloc, lengthsLocal); // create an array for keeping the lengths of each dimension GeneratorHelper.GenerateLoop(generator, rankLocal, i => { generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Ldloc, i); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Brfalse, lengthIsZeroLabel); generator.Emit(OpCodes.Ldc_I4_1); generator.Emit(OpCodes.Stloc, isNotEmptyArrayLocal); generator.MarkLabel(lengthIsZeroLabel); generator.Emit(OpCodes.Stelem, typeof(Int32)); // populate the lengths with values read from stream }); PushTypeOntoStack(elementFormalType); generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(x => Array.CreateInstance(null, new int[0]))); generator.Emit(OpCodes.Stloc, arrayLocal); // create an multidimensional array SaveNewDeserializedObject(objectIdLocal, () => { generator.Emit(OpCodes.Ldloc, arrayLocal); }); // store created array to deserialized obejcts collection generator.Emit(OpCodes.Ldloc, rankLocal); generator.Emit(OpCodes.Newarr, typeof(Int32)); generator.Emit(OpCodes.Stloc, positionLocal); // create an array for keeping the current position of each dimension generator.Emit(OpCodes.Ldloc, isNotEmptyArrayLocal); generator.Emit(OpCodes.Stloc, loopControlLocal); // initialize loop control variable generator.MarkLabel(loopBeginLabel); generator.Emit(OpCodes.Ldloc, loopControlLocal); generator.Emit(OpCodes.Brfalse, loopEndLabel); generator.Emit(OpCodes.Ldloc, arrayLocal); GenerateReadField(elementFormalType, true); generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(a => a.SetValue(null, new int[0]))); generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Ldloc, rankLocal); GenerateCodeFCall <int[], int[], int, bool>((counter, sizes, ranks) => { var currentRank = ranks - 1; while (currentRank >= 0) { counter[currentRank]++; if (counter[currentRank] < sizes[currentRank]) { return(true); } counter[currentRank] = 0; currentRank--; } return(false); }); generator.Emit(OpCodes.Stloc, loopControlLocal); generator.Emit(OpCodes.Br, loopBeginLabel); generator.MarkLabel(loopEndLabel); }
private void GenerateReadArray(Type arrayType, LocalBuilder objectIdLocal) { var isMultidimensional = arrayType.GetArrayRank() > 1; var elementFormalType = arrayType.GetElementType(); var rankLocal = generator.DeclareLocal(typeof(Int32)); var lengthsLocal = isMultidimensional ? generator.DeclareLocal(typeof(Int32[])) : generator.DeclareLocal(typeof(Int32)); var arrayLocal = generator.DeclareLocal(typeof(Array)); var positionLocal = isMultidimensional ? generator.DeclareLocal(typeof(Int32[])) : generator.DeclareLocal(typeof(Int32)); var loopControlLocal = generator.DeclareLocal(typeof(int)); // type is int not bool to reuse array length directly var loopBeginLabel = generator.DefineLabel(); var loopEndLabel = generator.DefineLabel(); var nonZeroLengthLabel = generator.DefineLabel(); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Stloc, rankLocal); // read amount of dimensions of the array if (isMultidimensional) { generator.Emit(OpCodes.Ldc_I4_1); generator.Emit(OpCodes.Stloc, loopControlLocal); generator.Emit(OpCodes.Ldloc, rankLocal); generator.Emit(OpCodes.Newarr, typeof(Int32)); generator.Emit(OpCodes.Stloc, lengthsLocal); // create an array for keeping the lengths of each dimension GeneratorHelper.GenerateLoop(generator, rankLocal, i => { generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Ldloc, i); GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Brtrue, nonZeroLengthLabel); generator.Emit(OpCodes.Ldc_I4_0); generator.Emit(OpCodes.Stloc, loopControlLocal); generator.MarkLabel(nonZeroLengthLabel); generator.Emit(OpCodes.Stelem, typeof(Int32)); // populate the lengths with values read from stream }); } else { GenerateReadPrimitive(typeof(Int32)); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Stloc, lengthsLocal); generator.Emit(OpCodes.Stloc, loopControlLocal); } PushTypeOntoStack(elementFormalType); if (isMultidimensional) { generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(x => Array.CreateInstance(null, new int[0]))); generator.Emit(OpCodes.Stloc, arrayLocal); // create an multidimensional array } else { generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(x => Array.CreateInstance(null, 0))); generator.Emit(OpCodes.Stloc, arrayLocal); // create a one dimensional array } SaveNewDeserializedObject(objectIdLocal, () => { generator.Emit(OpCodes.Ldloc, arrayLocal); }); // store created array to deserialized obejcts collection if (isMultidimensional) { generator.Emit(OpCodes.Ldloc, rankLocal); generator.Emit(OpCodes.Newarr, typeof(Int32)); generator.Emit(OpCodes.Stloc, positionLocal); // create an array for keeping the current position of each dimension } generator.MarkLabel(loopBeginLabel); generator.Emit(OpCodes.Ldloc, loopControlLocal); generator.Emit(OpCodes.Brfalse, loopEndLabel); generator.Emit(OpCodes.Ldloc, arrayLocal); generator.Emit(OpCodes.Castclass, arrayType); if (isMultidimensional) { GenerateReadField(elementFormalType); generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <Array>(a => a.SetValue(null, new int[0]))); } else { generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Ldelema, elementFormalType); GenerateReadField(elementFormalType, false); generator.Emit(OpCodes.Stobj, elementFormalType); } if (isMultidimensional) { generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Ldloc, rankLocal); GenerateCodeFCall <int[], int[], int, bool>((counter, sizes, ranks) => { var currentRank = ranks - 1; while (currentRank >= 0) { counter[currentRank]++; if (counter[currentRank] < sizes[currentRank]) { return(true); } counter[currentRank] = 0; currentRank--; } return(false); }); } else { generator.Emit(OpCodes.Ldloc, positionLocal); generator.Emit(OpCodes.Ldc_I4_1); generator.Emit(OpCodes.Add); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Stloc, positionLocal); generator.Emit(OpCodes.Ldloc, lengthsLocal); generator.Emit(OpCodes.Clt); } generator.Emit(OpCodes.Stloc, loopControlLocal); generator.Emit(OpCodes.Br, loopBeginLabel); generator.MarkLabel(loopEndLabel); }