Exemplo n.º 1
0
        private static void GenerateWriteValue(WriterGenerationContext context, Variable valueLocal, Type formalType)
        {
            ObjectWriter.CheckLegality(formalType);
            if (formalType.IsEnum)
            {
                formalType = Enum.GetUnderlyingType(formalType);
            }
            var writeMethod = typeof(PrimitiveWriter).GetMethod("Write", new[] { formalType });

            // if this method is null, then it is a non-primitive (i.e. custom) struct
            if (writeMethod != null)
            {
                context.PushPrimitiveWriterOntoStack();
                context.Generator.PushVariableOntoStack(valueLocal);
                context.Generator.Emit(OpCodes.Call, writeMethod);
                return;
            }
            var nullableUnderlyingType = Nullable.GetUnderlyingType(formalType);

            if (nullableUnderlyingType != null)
            {
                var hasValueLabel = context.Generator.DefineLabel();
                var finishLabel   = context.Generator.DefineLabel();

                var underlyingValueLocal = context.Generator.DeclareLocal(nullableUnderlyingType);
                var underlyingVariable   = new Variable(underlyingValueLocal);

                context.PushPrimitiveWriterOntoStack();
                context.Generator.PushVariableAddressOntoStack(valueLocal);
                context.Generator.Emit(OpCodes.Call, formalType.GetProperty("HasValue").GetGetMethod());
                context.Generator.Emit(OpCodes.Brtrue_S, hasValueLabel);
                context.Generator.PushIntegerOntoStack(0);
                context.Generator.Call <PrimitiveWriter>(x => x.Write(false));
                context.Generator.Emit(OpCodes.Br_S, finishLabel);

                context.Generator.MarkLabel(hasValueLabel);
                context.Generator.PushIntegerOntoStack(1);
                context.Generator.Call <PrimitiveWriter>(x => x.Write(false));

                context.Generator.PushVariableAddressOntoStack(valueLocal);
                context.Generator.Emit(OpCodes.Call, formalType.GetProperty("Value").GetGetMethod());
                context.Generator.StoreLocalValueFromStack(underlyingValueLocal);

                GenerateWriteValue(context, underlyingVariable, nullableUnderlyingType);

                context.Generator.MarkLabel(finishLabel);
                return;
            }

            GenerateWriteFields(context, valueLocal, formalType);
        }
Exemplo n.º 2
0
        internal WriteMethodGenerator(Type typeToGenerate)
        {
            typeWeAreGeneratingFor = typeToGenerate;
            ObjectWriter.CheckLegality(typeToGenerate);
            InitializeMethodInfos();
            if (!typeToGenerate.IsArray)
            {
                dynamicMethod = new DynamicMethod(string.Format("Write_{0}", typeToGenerate.Name), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
                                                  typeof(void), ParameterTypes, typeToGenerate, true);
            }
            else
            {
                var methodNo = Interlocked.Increment(ref WriteArrayMethodCounter);
                dynamicMethod = new DynamicMethod(string.Format("WriteArray{0}_{1}", methodNo, typeToGenerate.Name), null, ParameterTypes, true);
            }
            generator = dynamicMethod.GetILGenerator();

            // preserialization callbacks
            GenerateInvokeCallback(typeToGenerate, typeof(PreSerializationAttribute));
            var exceptionBlockNeeded = Helpers.GetMethodsWithAttribute(typeof(PostSerializationAttribute), typeToGenerate).Any() ||
                                       Helpers.GetMethodsWithAttribute(typeof(LatePostSerializationAttribute), typeToGenerate).Any();

            if (exceptionBlockNeeded)
            {
                generator.BeginExceptionBlock();
            }

            if (!GenerateSpecialWrite(typeToGenerate))
            {
                GenerateWriteFields(gen =>
                {
                    gen.Emit(OpCodes.Ldarg_2);
                }, typeToGenerate);
            }
            if (exceptionBlockNeeded)
            {
                generator.BeginFinallyBlock();
            }
            // postserialization callbacks
            GenerateInvokeCallback(typeToGenerate, typeof(PostSerializationAttribute));
            GenerateAddCallbackToInvokeList(typeToGenerate, typeof(LatePostSerializationAttribute));
            if (exceptionBlockNeeded)
            {
                generator.EndExceptionBlock();
            }
            generator.Emit(OpCodes.Ret);
        }
Exemplo n.º 3
0
        private void GenerateWriteValue(Action <ILGenerator> putValueToWriteOnTop, Type formalType)
        {
            ObjectWriter.CheckLegality(formalType, typeWeAreGeneratingFor);
            if (formalType.IsEnum)
            {
                formalType = Enum.GetUnderlyingType(formalType);
            }
            var writeMethod = typeof(PrimitiveWriter).GetMethod("Write", new [] { formalType });

            // if this method is null, then it is a non-primitive (i.e. custom) struct
            if (writeMethod != null)
            {
                generator.Emit(OpCodes.Ldarg_1); // primitive writer waits there
                putValueToWriteOnTop(generator);
                generator.Emit(OpCodes.Call, writeMethod);
                return;
            }
            var nullableUnderlyingType = Nullable.GetUnderlyingType(formalType);

            if (nullableUnderlyingType != null)
            {
                var hasValue   = generator.DefineLabel();
                var finish     = generator.DefineLabel();
                var localIndex = generator.DeclareLocal(formalType).LocalIndex;
                generator.Emit(OpCodes.Ldarg_1); // primitiveWriter
                putValueToWriteOnTop(generator);
                generator.Emit(OpCodes.Stloc_S, localIndex);
                generator.Emit(OpCodes.Ldloca_S, localIndex);
                generator.Emit(OpCodes.Call, formalType.GetProperty("HasValue").GetGetMethod());
                generator.Emit(OpCodes.Brtrue_S, hasValue);
                generator.Emit(OpCodes.Ldc_I4_0);
                generator.Emit(OpCodes.Call, primitiveWriterWriteBoolean);
                generator.Emit(OpCodes.Br, finish);
                generator.MarkLabel(hasValue);
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Call, primitiveWriterWriteBoolean);
                GenerateWriteValue(gen =>
                {
                    generator.Emit(OpCodes.Ldloca_S, localIndex);
                    generator.Emit(OpCodes.Call, formalType.GetProperty("Value").GetGetMethod());
                }, nullableUnderlyingType);
                generator.MarkLabel(finish);
                return;
            }

            if (formalType.IsGenericType && formalType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
            {
                var keyValueTypes = formalType.GetGenericArguments();
                var localIndex    = generator.DeclareLocal(formalType).LocalIndex;
                GenerateWriteType(gen =>
                {
                    putValueToWriteOnTop(gen);
                    // TODO: is there a better method of getting address?
                    // don't think so, looking at
                    // http://stackoverflow.com/questions/76274/
                    // we *may* do a little optimization if this value write takes
                    // place when dictionary is serialized (current KVP is stored in
                    // local 1 in such situation); the KVP may be, however, written
                    // independently
                    gen.Emit(OpCodes.Stloc_S, localIndex);
                    gen.Emit(OpCodes.Ldloca_S, localIndex);
                    gen.Emit(OpCodes.Call, formalType.GetProperty("Key").GetGetMethod());
                }, keyValueTypes[0]);
                GenerateWriteType(gen =>
                {
                    // we assume here that the key write was invoked earlier (it should be
                    // if we're conforming to the protocol), so KeyValuePair is already
                    // stored as local
                    gen.Emit(OpCodes.Ldloca_S, localIndex);
                    gen.Emit(OpCodes.Call, formalType.GetProperty("Value").GetGetMethod());
                }, keyValueTypes[1]);
            }
            else
            {
                GenerateWriteFields(putValueToWriteOnTop, formalType);
            }
        }
Exemplo n.º 4
0
        internal WriteMethodGenerator(Type typeToGenerate, bool treatCollectionAsUserObject, int surrogateId, FieldInfo typeIndicesField, FieldInfo surrogatesField, FieldInfo typeIdWrittenField,
                                      MethodInfo writeObjectMethod)
        {
            typeWeAreGeneratingFor = typeToGenerate;
            ObjectWriter.CheckLegality(typeToGenerate);
            InitializeMethodInfos();
            if (!typeToGenerate.IsArray)
            {
                dynamicMethod = new DynamicMethod(string.Format("Write_{0}", typeToGenerate.Name), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
                                                  typeof(void), ParameterTypes, typeToGenerate, true);
            }
            else
            {
                var methodNo = Interlocked.Increment(ref WriteArrayMethodCounter);
                dynamicMethod = new DynamicMethod(string.Format("WriteArray{0}_{1}", methodNo, typeToGenerate.Name), null, ParameterTypes, true);
            }
            generator = dynamicMethod.GetILGenerator();

            // surrogates
            if (surrogateId != -1)
            {
                generator.Emit(OpCodes.Ldarg_0); // used (1)

                // obtain surrogate factory
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, surrogatesField);
                generator.Emit(OpCodes.Ldc_I4, surrogateId);
                generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <InheritanceAwareList <Delegate> >(x => x.GetByIndex(0)));

                // call surrogate factory to obtain surrogate object
                var delegateType = typeof(Func <,>).MakeGenericType(typeToGenerate, typeof(object));
                generator.Emit(OpCodes.Castclass, delegateType);
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Call, delegateType.GetMethod("Invoke"));

                // jump to surrogate serialization
                generator.Emit(OpCodes.Call, writeObjectMethod); // (1) here
                generator.Emit(OpCodes.Ret);
                return;
            }

            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, typeIdWrittenField);
            var omitWriteIdLabel = generator.DefineLabel();

            generator.Emit(OpCodes.Brtrue, omitWriteIdLabel);

            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, typeIndicesField);
            generator.Emit(OpCodes.Ldtoken, typeToGenerate);
            generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <RuntimeTypeHandle, Type>(o => Type.GetTypeFromHandle(o)));
            generator.Emit(OpCodes.Call, Helpers.GetMethodInfo(() => TypeDescriptor.CreateFromType(null)));
            generator.Emit(OpCodes.Call, typeof(Dictionary <TypeDescriptor, int>).GetMethod("get_Item"));
            generator.Emit(OpCodes.Call, Helpers.GetMethodInfo <PrimitiveWriter>(x => x.Write(0)));

            generator.MarkLabel(omitWriteIdLabel);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldc_I4_0);
            generator.Emit(OpCodes.Stfld, typeIdWrittenField);

            // preserialization callbacks
            GenerateInvokeCallback(typeToGenerate, typeof(PreSerializationAttribute));
            var exceptionBlockNeeded = Helpers.GetMethodsWithAttribute(typeof(PostSerializationAttribute), typeToGenerate).Any() ||
                                       Helpers.GetMethodsWithAttribute(typeof(LatePostSerializationAttribute), typeToGenerate).Any();

            if (exceptionBlockNeeded)
            {
                generator.BeginExceptionBlock();
            }

            if (!GenerateSpecialWrite(typeToGenerate, treatCollectionAsUserObject))
            {
                GenerateWriteFields(gen =>
                {
                    gen.Emit(OpCodes.Ldarg_2);
                }, typeToGenerate);
            }
            if (exceptionBlockNeeded)
            {
                generator.BeginFinallyBlock();
            }
            // postserialization callbacks
            GenerateInvokeCallback(typeToGenerate, typeof(PostSerializationAttribute));
            GenerateAddCallbackToInvokeList(typeToGenerate, typeof(LatePostSerializationAttribute));
            if (exceptionBlockNeeded)
            {
                generator.EndExceptionBlock();
            }
            generator.Emit(OpCodes.Ret);
        }
Exemplo n.º 5
0
 internal WriteMethodGenerator(Type typeToGenerate, bool disableStamping, bool treatCollectionAsUserObject)
     : base(typeToGenerate, disableStamping, treatCollectionAsUserObject)
 {
     ObjectWriter.CheckLegality(typeToGenerate);
 }