Beispiel #1
0
        private SizeCounterDelegate BuildCounter(Type type, bool ignoreCustomSerialization)
        {
            IntPtr counter = GetCounter(type, ignoreCustomSerialization);

            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(object), typeof(bool), typeof(WriterContext) }, GetType(), true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldarg(0); // stack: [obj]
                if (type.IsValueType)
                {
                    il.Unbox_Any(type); // stack: [(type)obj]
                }
                else
                {
                    il.Castclass(type);                                                                                  // stack: [(type)obj]
                }
                il.Ldarg(1);                                                                                             // stack: [(type)obj, writeEmpty]
                il.Ldarg(2);                                                                                             // stack: [(type)obj, writeEmpty, context]
                il.Ldc_IntPtr(counter);                                                                                  // stack: [(type)obj, writeEmpty, context, counter]
                il.Calli(CallingConventions.Standard, typeof(int), new[] { type, typeof(bool), typeof(WriterContext) }); // counter((type)obj, writeEmpty, context); stack: []
                il.Ret();
            }

            return((SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate)));
        }
Beispiel #2
0
        private WriterDelegate BuildWriter(Type type, bool ignoreCustomSerialization)
        {
            IntPtr writer = GetWriter(type, ignoreCustomSerialization);

            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }, module, true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldarg(0); // stack: [obj]
                if (type.IsValueType)
                {
                    il.Unbox_Any(type); // stack: [(type)obj]
                }
                else
                {
                    il.Castclass(type);                                                                                                                                // stack: [(type)obj]
                }
                il.Ldarg(1);                                                                                                                                           // stack: [(type)obj, writeEmpty]
                il.Ldarg(2);                                                                                                                                           // stack: [(type)obj, writeEmpty, result]
                il.Ldarg(3);                                                                                                                                           // stack: [(type)obj, writeEmpty, result, ref index]
                il.Ldarg(4);                                                                                                                                           // stack: [(type)obj, writeEmpty, result, ref index, context]
                il.Ldc_IntPtr(writer);
                il.Calli(CallingConventions.Standard, typeof(void), new[] { type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }); // writer.write<T>((type)obj, writeEmpty, result, ref index, context); stack: []
                il.Ret();
            }

            return((WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate)));
        }
        private static void EmitDefaultTypeValue(GroboIL il, Type type)
        {
            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.Boolean:
            case TypeCode.Char:
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
                il.Ldc_I4(0);
                return;

            case TypeCode.Int64:
            case TypeCode.UInt64:
                il.Ldc_I8(0);
                return;

            case TypeCode.Single:
                il.Ldc_R4(0f);
                return;

            case TypeCode.Double:
                il.Ldc_R8(0d);
                return;
            }

            if (type.IsPointer || type == typeof(UIntPtr) || type == typeof(IntPtr))
            {
                il.Ldc_IntPtr(IntPtr.Zero);
                il.Conv <UIntPtr>();
            }
            else if (type.IsEnum)
            {
                EmitDefaultTypeValue(il, Enum.GetUnderlyingType(type));
            }
            else if (type.IsValueType)
            {
                var local = il.DeclareLocal(type);
                il.Ldloca(local);
                il.Initobj(type);
                il.Ldloc(local);
            }
            else
            {
                il.Ldnull();
            }
        }
        public static void LoadReader(GroboIL il, Type type, ReaderTypeBuilderContext context)
        {
            var counter = context.GetReader(type);

            if (counter.Pointer != IntPtr.Zero)
            {
                il.Ldc_IntPtr(counter.Pointer);
            }
            else
            {
                il.Ldfld(context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic));
                il.Ldc_I4(counter.Index);
                il.Ldelem(typeof(IntPtr));
            }
        }
        public void CallWriter(GroboIL il, Type type)
        {
            var counter = Context.GetWriter(type);

            if (counter.Pointer != IntPtr.Zero)
            {
                il.Ldc_IntPtr(counter.Pointer);
            }
            else
            {
                il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic));
                il.Ldc_I4(counter.Index);
                il.Ldelem(typeof(IntPtr));
            }
            il.Calli(CallingConventions.Standard, typeof(void), new[] { type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) });
        }
Beispiel #6
0
        private SizeCounterDelegate <T> BuildCounter <T>(bool ignoreCustomSerialization)
        {
            var    type    = typeof(T);
            IntPtr counter = GetCounter(type, ignoreCustomSerialization);

            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { type, typeof(bool), typeof(WriterContext) }, GetType(), true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldarg(0);                                                                                             // stack: [obj]
                il.Ldarg(1);                                                                                             // stack: [obj, writeEmpty]
                il.Ldarg(2);                                                                                             // stack: [obj, writeEmpty, context]
                il.Ldc_IntPtr(counter);                                                                                  // stack: [obj, writeEmpty, context, counter]
                il.Calli(CallingConventions.Standard, typeof(int), new[] { type, typeof(bool), typeof(WriterContext) }); // counter(obj, writeEmpty, context); stack: []
                il.Ret();
            }
            return((SizeCounterDelegate <T>)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate <T>)));
        }
        private static void EmitValue(GroboIL il, object value)
        {
            //value.GetType() is the "real" type, only all pointers are UIntPtr and nullables are BoxedNullable
            //It can be:
            //Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Enum, IntPtr, UIntPtr
            //Or their nullable equivalents
            //Or string
            switch (value)
            {
            case bool boolean: il.Ldc_I4(boolean ? 1 : 0); break;

            case char character: il.Ldc_I4(character); break;

            case sbyte int8: il.Ldc_I4(int8); break;

            case byte uint8: il.Ldc_I4(uint8); break;

            case short int16: il.Ldc_I4(int16); break;

            case ushort uint16: il.Ldc_I4(uint16); break;

            case int int32: il.Ldc_I4(int32); break;

            case uint uint32: il.Ldc_I4((int)uint32); break;

            case long int64: il.Ldc_I8(int64); break;

            case ulong uint64: il.Ldc_I8((long)uint64); break;

            case float float32: il.Ldc_R4(float32); break;

            case double float64: il.Ldc_R8(float64); break;

            case decimal decimal128: il.LdDec(decimal128); break;

            case DateTime dateTime:
                var local = il.DeclareLocal(typeof(DateTime));
                il.Ldloca(local);
                il.Ldc_I8(dateTime.Ticks);
                il.Ldc_I4((int)dateTime.Kind);
                il.Call(typeof(DateTime).GetConstructor(new[] { typeof(long), typeof(DateTimeKind) }));
                il.Ldloc(local);
                break;

            case UIntPtr unint: il.Ldc_IntPtr(Unsafe.As <UIntPtr, IntPtr>(ref unint)); break;

            case IntPtr nint: il.Ldc_IntPtr(nint); break;

            case Enum enumeration:
                var underlyingType  = Enum.GetUnderlyingType(enumeration.GetType());
                var underlyingValue = Convert.ChangeType(enumeration, underlyingType);
                EmitValue(il, underlyingValue);
                break;

            case BoxedNullable boxedNullable:
                EmitValue(il, boxedNullable.UnderlyingValue);
                il.Newobj(boxedNullable.NullableType.GetConstructor(new[] { boxedNullable.UnderlyingType }));
                break;

            case string str: il.Ldstr(str); break;

            default: throw new ArgumentException($"Value {value} of type {value.GetType()} is not supported by the emitter.");
            }
        }