예제 #1
0
        private static void GenerateDebugTrace(string traceString, ILGenerator il, ILGenContext context)
        {
#if DEBUG
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, traceString);
            il.Emit(OpCodes.Callvirt,
                    context.Serialize ? Methods.SerializeContext_DebugTrace : Methods.DeserializeContext_DebugTrace);
#endif
        }
예제 #2
0
 private static void GenerateSerializeValueTypeField(Type type, FieldInfo field, ILGenerator il,
                                                     ILGenContext context)
 {
     Debug.Assert(field.FieldType.IsValueType);
     il.Emit(OpCodes.Ldarg_0);             // context
     il.Emit(OpCodes.Ldarg_1);             // bw
     il.Emit(OpCodes.Ldarg_2);             // obj
     il.Emit(OpCodes.Ldflda, field);       // obj.'field' (byref)
     il.Emit(OpCodes.Call, context.fieldSerializationMethods[field.FieldType]);
 }
예제 #3
0
 private static void GenerateSerializePrimitiveField(Type type, FieldInfo field, ILGenerator il,
                                                     ILGenContext context)
 {
     if (context.Serialize)
     {
         il.Emit(OpCodes.Ldarg_1);                 // bw
         il.Emit(OpCodes.Ldarg_2);                 // obj
         il.Emit(OpCodes.Ldfld, field);            // obj.'field'
         il.Emit(OpCodes.Callvirt, Methods.BinaryWriterPrimitive[field.FieldType]);
     }
     else
     {
         il.Emit(OpCodes.Ldarg_2);                 // obj
         il.Emit(OpCodes.Ldarg_1);                 // br
         il.Emit(OpCodes.Callvirt, Methods.BinaryReaderPrimitive[field.FieldType]);
         il.Emit(OpCodes.Stfld, field);            // obj.'field' = ...
     }
 }
예제 #4
0
 private static void GenerateReferenceTypeLeaveObject(Type type, ILGenerator il, ILGenContext context)
 {
     if (context.Serialize)             // Deserialize doesn't have LeaveObject
     {
         il.Emit(OpCodes.Ldarg_0);
         il.Emit(OpCodes.Callvirt, Methods.SerializeContext_LeaveObject);
     }
 }
예제 #5
0
 private static void GenerateReferenceTypeVisitObject(Type type, ILGenerator il, ILGenContext context)
 {
     il.Emit(OpCodes.Ldarg_0);
     il.Emit(OpCodes.Ldarg_2);
     il.Emit(OpCodes.Callvirt,
             context.Serialize ? Methods.SerializeContext_VisitObject : Methods.DeserializeContext_VisitObject);
 }
예제 #6
0
        // Reference type entry point:
        public static void GenerateReferenceTypeSerializationMethod(Type type, ILGenerator il, ILGenContext context)
        {
            Debug.Assert(!type.IsValueType);

            if (context.Serialize
                )         // Serialize visits and leaves objects like a stack (including up the inheritance hierarchy within a single object instance)
            {
                GenerateReferenceTypeVisitObject(type, il, context);
            }

            var baseTypeSerializer = context.referenceTypeSerializationMethods[type.BaseType];

            if (baseTypeSerializer != null)
            {
                // Serialize the base type:
                // ReferenceType[De]Serializer(context, bw, (BaseType)obj);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Call, baseTypeSerializer);
            }
            else if (!context.Serialize
                     )    // Deserialize visits objects once only to get their reference (so only visit the base)
            {
                GenerateReferenceTypeVisitObject(type, il, context);
            }

            GenerateSerializeAllTypeFields(type, il, context);

            GenerateReferenceTypeLeaveObject(type, il, context);
            il.Emit(OpCodes.Ret);
        }
예제 #7
0
 private static void GenerateClearField(Type type, FieldInfo field, ILGenerator il, ILGenContext context)
 {
     il.Emit(OpCodes.Ldarg_2);
     il.Emit(OpCodes.Ldflda, field);
     il.Emit(OpCodes.Initobj, field.FieldType);
 }
예제 #8
0
        private static void GenerateSerializeField(Type type, FieldInfo field, ILGenerator il, ILGenContext context)
        {
            // NOTE: Delegate and array fields are handled by built-in custom field methods (via custom method providers)
            //       (so get handled as reference field types)


            if (IsIgnoredField(field))
            {
                return;
            }


            if (field.FieldType.IsPrimitive)
            {
                GenerateSerializePrimitiveField(type, field, il, context);                 // Inline serialize
                return;
            }

            if (field.FieldType.IsPointer)
            {
                return;                 // Do nothing (should explode?)
            }
            if (field.FieldType.IsValueType)
            {
                GenerateSerializeValueTypeField(type, field, il, context);
            }
            else
            {
                GenerateSerializeReferenceTypeField(type, field, il, context);
            }
        }
예제 #9
0
        // Value type entry point:
        public static void GenerateValueTypeSerializationMethod(Type type, ILGenerator il, ILGenContext context)
        {
            Debug.Assert(type.IsValueType);

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                GenerateNullableTypeSerializeMethod(type, il, context);
            }
            else
            {
                GenerateSerializeAllTypeFields(type, il, context);
                il.Emit(OpCodes.Ret);
            }
        }
예제 #10
0
        private static void GenerateSerializeAllTypeFields(Type type, ILGenerator il, ILGenContext context)
        {
            //
            // Pack all bool fields into bytes:

            var boolFields = type.GetFields(TypeDiscovery.allInstanceDeclared)
                             .Where(f => f.FieldType == typeof(bool))
                             .Where(f => !IsIgnoredField(f))
                             .NetworkOrder(fi => fi.Name).ToArray();

            if (boolFields.Length > 0)
            {
                var bytesRequired = (boolFields.Length + 7) / 8;

                if (context.Serialize)
                {
                    for (var i = 0; i < bytesRequired; i++)
                    {
                        var bitsRequired = Math.Min(8, boolFields.Length - i * 8);
                        Debug.Assert(bitsRequired > 0);

#if DEBUG
                        var traceString = "Boolean fields (" + i + "): " + string.Join(", ",
                                                                                       boolFields.Select(f => f.Name).ToArray(), i * 8, bitsRequired);
                        GenerateDebugTrace(traceString, il, context);
#endif

                        il.Emit(OpCodes.Ldarg_1);                         // bw.(...)

                        for (var j = 0; j < bitsRequired; j++)
                        {
                            // const x = (1 << j);
                            // (obj.value ? x : 0u)
                            il.Emit(OpCodes.Ldarg_2);
                            il.Emit(OpCodes.Ldfld, boolFields[i * 8 + j]);
                            var labelTrue = il.DefineLabel();
                            il.Emit(OpCodes.Brtrue_S, labelTrue);
                            il.Emit(OpCodes.Ldc_I4_0);
                            var labelEnd = il.DefineLabel();
                            il.Emit(OpCodes.Br_S, labelEnd);
                            il.MarkLabel(labelTrue);
                            il.EmitLdc_I4(1 << j);
                            il.MarkLabel(labelEnd);

                            // (...) | (...)
                            if (j != 0)
                            {
                                il.Emit(OpCodes.Or);
                            }
                        }

                        // bw.Write((byte)(...));
                        il.Emit(OpCodes.Conv_U1);
                        il.Emit(OpCodes.Callvirt, Methods.BinaryWriter_WriteByte);
                    }
                }
                else
                {
                    for (var i = 0; i < bytesRequired; i++)
                    {
                        var bitsRequired = Math.Min(8, boolFields.Length - i * 8);
                        Debug.Assert(bitsRequired > 0);

#if DEBUG
                        var traceString = "Boolean fields (" + i + "): " + string.Join(", ",
                                                                                       boolFields.Select(f => f.Name).ToArray(), i * 8, bitsRequired);
                        GenerateDebugTrace(traceString, il, context);
#endif

                        // uint data;
                        var localValue = il.DeclareLocal(typeof(uint));

                        // data = br.ReadByte();
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Callvirt, Methods.BinaryReader_ReadByte);
                        il.Emit(OpCodes.Stloc, localValue);                         // <- NOTE: Emits short form

                        for (var j = 0; j < bitsRequired; j++)
                        {
                            // const x = (1 << j);
                            // obj.value = (data & x) > 0;
                            il.Emit(OpCodes.Ldarg_2);
                            il.Emit(OpCodes.Ldloc, localValue);                             // <- NOTE: Emits short form
                            il.EmitLdc_I4(1 << j);
                            il.Emit(OpCodes.And);
                            il.Emit(OpCodes.Ldc_I4_0);
                            il.Emit(OpCodes.Cgt_Un);
                            il.Emit(OpCodes.Stfld, boolFields[i * 8 + j]);
                        }
                    }
                }
            }


            //
            // Then handle all other fields:

            // NOTE: I have tried sorting this for cache coherency (primatives, then value types, then refrence types)
            //       and it is difficult to tell if it makes a real difference (due to measurement error),
            //       but if it does it seems slightly worse than just having the fields in alphabetical order.
            //       (Speculation: it might be better to mix in a couple of value-type writes every time we come back
            //        to write a pointer for a reference type. Best case may be to duplicate the field order from
            //        the CLR (can sort by MethodInfo.MetadataToken, apparently) - but this defeats the
            //        purpose of NetworkOrder, because that that is compile-time dependent.)
            //       -AR
            var nonBoolFields = type.GetFields(TypeDiscovery.allInstanceDeclared)
                                .Where(f => f.FieldType != typeof(bool)).NetworkOrder(f => f.Name);

            foreach (var field in nonBoolFields)
            {
                GenerateDebugTrace(field.Name, il, context);
                GenerateSerializeField(type, field, il, context);
            }
        }
예제 #11
0
        private static void GenerateNullableTypeSerializeMethod(Type type, ILGenerator il, ILGenContext context)
        {
            var fieldHasValue = type.GetField(HAS_VALUE_FIELD, TypeDiscovery.allInstanceDeclared);
            var fieldValue    = type.GetField("value", TypeDiscovery.allInstanceDeclared);

            // Serialize obj.hasValue
            GenerateSerializePrimitiveField(type, fieldHasValue, il, context);

            // if(obj.hasValue)
            var end = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_2);
            il.Emit(OpCodes.Ldfld, fieldHasValue);
            il.Emit(OpCodes.Brfalse, end);

            //     Serialize obj.value
            GenerateSerializeField(type, fieldValue, il, context);

            if (context.Deserialize)             // Return before the else statement (serialize can just drop through)
            {
                il.Emit(OpCodes.Ret);
            }

            // else
            il.MarkLabel(end);
            if (context.Deserialize)
            {
                GenerateClearField(type, fieldValue, il, context);
            }

            il.Emit(OpCodes.Ret);
        }