Beispiel #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
                }
            });
        }
Beispiel #2
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) }));
            });
        }
Beispiel #3
0
        private void GenerateFillCollection(Type elementFormalType, Type collectionType, LocalBuilder objectIdLocal)
        {
            var countLocal = generator.DeclareLocal(typeof(Int32));

            GenerateReadPrimitive(typeof(Int32));
            generator.Emit(OpCodes.Stloc, 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 = generator.DeclareLocal(elementFormalType.MakeArrayType());

                generator.Emit(OpCodes.Ldloc, countLocal);
                generator.Emit(OpCodes.Newarr, elementFormalType);
                generator.Emit(OpCodes.Stloc, tempArrLocal);                 // creates temporal array

                GeneratorHelper.GenerateLoop(generator, countLocal, cl => {
                    generator.Emit(OpCodes.Ldloc, tempArrLocal);
                    generator.Emit(OpCodes.Ldloc, cl);
                    GenerateReadField(elementFormalType, false);
                    generator.Emit(OpCodes.Stelem, elementFormalType);
                });

                GeneratorHelper.GenerateLoop(generator, countLocal, cl => {
                    PushDeserializedObjectOntoStack(objectIdLocal);
                    generator.Emit(OpCodes.Castclass, collectionType);

                    generator.Emit(OpCodes.Ldloc, tempArrLocal);
                    generator.Emit(OpCodes.Ldloc, cl);
                    generator.Emit(OpCodes.Ldelem, elementFormalType);
                    generator.Emit(OpCodes.Callvirt, collectionType.GetMethod("Push"));
                }, true);
            }
            else
            {
                GeneratorHelper.GenerateLoop(generator, countLocal, cl => {
                    PushDeserializedObjectOntoStack(objectIdLocal);
                    generator.Emit(OpCodes.Castclass, collectionType);
                    GenerateReadField(elementFormalType, false);
                    generator.Emit(OpCodes.Callvirt, addMethod);

                    if (addMethod.ReturnType != typeof(void))
                    {
                        generator.Emit(OpCodes.Pop);                         // remove returned unused value from stack
                    }
                });
            }
        }
Beispiel #4
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);
                });
            });
        }
Beispiel #5
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);
        }