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 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 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 } }); } }
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 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); }