Пример #1
0
        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 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
                    }
                });
            }
        }
Пример #3
0
        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);
                });
            });
        }
Пример #4
0
        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) }));
            });
        }
Пример #5
0
        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);
                });
            });
        }
Пример #6
0
        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);
            });
        }
Пример #7
0
        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);
            });
        }
Пример #8
0
 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);
        }
        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);
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
        }