예제 #1
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            BinaryStruct.WriteSizeChecker(il, buffer, offset, 8);
            var arr = il.DeclareLocal(typeof(byte[]));
            var v   = il.DeclareLocal(typeof(DateTime));
            var t   = il.DeclareLocal(typeof(TimeSpan));

            if (!listValue)
            {
                il.Ldloc(value);
                var v1 = il.DeclareLocal(typeof(DateTime));
                il.Call(prop.Getter);
                il.Stloc(v1);
                il.Ldloca(v1);
            }
            else
            {
                il.Ldloca(value);
            }

            il.Ldloca(v);
            il.Ldc_I4(1970);
            il.Ldc_I4(1);
            il.Ldc_I4(1);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Call(datetimeConstructor);


            il.Ldloc(v);
            il.Call(substractMethod);
            il.Stloc(t);
            il.Ldloca(t);
            il.Call(propertyGetter);

            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arr);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arr);
            il.Ldc_I4(0);
            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            for (int i = 1; i < 8; i++)
            {
                il.Ldloc(buffer);
                il.Ldloc(offset);
                il.Ldc_I4(i);
                il.Add();
                il.Ldloc(arr);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }
            BinaryStruct.WriteOffsetAppend(il, offset, 8);
        }
예제 #2
0
        private static void EmitNullableBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
        {
            // a.GetValueOrDefault() == b.GetValueOrDefault() && a.HasValue == b.HasValue;
            var type = getMethod.ReturnType;
            var getValueOrDefault = type.GetMethod("GetValueOrDefault", new Type[0]);
            var hasValue          = type.GetMethod("get_HasValue");
            var a = il.DeclareLocal(type);
            var b = il.DeclareLocal(type);

            il.Ldarg(0);
            il.Call(getMethod);
            il.Stloc(a);
            il.Ldarg(1);
            il.Call(getMethod);
            il.Stloc(b);

            il.Ldloca(a);
            il.Call(getValueOrDefault);
            il.Ldloca(b);
            il.Call(getValueOrDefault);
            il.Bne_Un(returnFalse);

            il.Ldloca(a);
            il.Call(hasValue);
            il.Ldloca(b);
            il.Call(hasValue);
            il.Bne_Un(returnFalse);
        }
예제 #3
0
        private static KeyValuePair <Delegate, IntPtr> GetReader(ReaderMethodBuilderContext context, Type type)
        {
            var method = new DynamicMethod("Read_" + type.Name + "_AndCastToObject_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)
            }, context.Context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(2);      // stack: [ref result]
                il.Ldarg(0);      // stack: [ref result, data]
                il.Ldarg(1);      // stack: [ref result, data, ref index]
                var value = il.DeclareLocal(type);
                il.Ldloca(value); // stack: [ref result, data, ref index, ref value]
                il.Ldarg(3);      // stack: [ref result, data, ref index, ref value, context]

                ReaderMethodBuilderContext.CallReader(il, type, context.Context);

                il.Ldloc(value); // stack: [ref result, value]
                if (type.IsValueType)
                {
                    il.Box(type); // stack: [ref result, (object)value]
                }
                else
                {
                    il.Castclass(type);
                }
                il.Stind(typeof(object)); // result = (object)value
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
예제 #4
0
        public static Func <Dictionary <string, object>, object> GenerateMethod(Type type)
        {
            var da = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName("dyn"),                 // call it whatever you want
                AssemblyBuilderAccess.RunAndSave);

            var dm = da.DefineDynamicModule("dyn_mod", "dyn.dll");
            var dt = dm.DefineType("dyn_type");



            var emiter = Emit <Func <int> > .NewDynamicMethod("MyMethod");

            var method = dt.DefineMethod(
                "Foo",
                MethodAttributes.Public | MethodAttributes.Static, typeof(object),
                new[] { typeof(Dictionary <string, object>) });

            method.DefineParameter(1, ParameterAttributes.None, "dictionary");


            using (var il = new GroboIL(method))
            {
                var target = il.DeclareLocal(type);
                var value  = il.DeclareLocal(typeof(object));

                il.Newobj(type.GetConstructor(Type.EmptyTypes)); // [Person]
                il.Stloc(target);                                // []
                foreach (var property in type.GetProperties())
                {
                    var label = il.DefineLabel("ifLabel");

                    il.Ldarg(0);                          // [Dictionary<String, Object>]
                    il.Ldstr(property.Name);              // [Dictionary<String, Object>, String]
                    il.Ldloca(value);                     // [Dictionary<String, Object>, String, Object&]
                    il.Call(typeof(Dictionary <string, object>)
                            .GetMethod("TryGetValue"));   // [Boolean]

                    il.Brfalse(label);                    // []

                    il.Ldloc(target);                     // [Person]
                    il.Ldloc(value);                      // [Person, Object]
                    il.Castclass(typeof(string));         // [Dictionary<String, Object>, String]
                    il.Call(property.GetSetMethod(true)); // []

                    il.MarkLabel(label);
                }

                il.Ldloc(target);
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }


            dt.CreateType();
            da.Save("dyn.dll");


            return((dic) => dt.GetMethod("Foo").Invoke(null, new object[] { dic }));
        }
예제 #5
0
        private void ValueToReference()
        {
            var local = Generator.DeclareLocal(typeof(BitsValue), "pointer");

            Generator.Stloc(local);
            Generator.Ldloca(local);
        }
        protected override bool EmitInternal(NewExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            context.EmitLoadArguments(node.Arguments.ToArray());
            // note ich: баг решарпера
            // ReSharper disable ConditionIsAlwaysTrueOrFalse
            // ReSharper disable HeuristicUnreachableCode
            GroboIL il = context.Il;

            if (node.Constructor != null)
            {
                il.Newobj(node.Constructor);
            }
            else
            {
                if (node.Type.IsValueType)
                {
                    using (var temp = context.DeclareLocal(node.Type))
                    {
                        il.Ldloca(temp);
                        il.Initobj(node.Type);
                        il.Ldloc(temp);
                    }
                }
                else
                {
                    throw new InvalidOperationException("Missing constructor for type '" + node.Type + "'");
                }
            }
            resultType = node.Type;
            // ReSharper restore ConditionIsAlwaysTrueOrFalse
            // ReSharper restore HeuristicUnreachableCode
            return(false);
        }
        protected override bool EmitInternal(MemberInitExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            ExpressionEmittersCollection.Emit(node.NewExpression, context, out resultType); // stack: [new obj(args)]
            GroboIL il = context.Il;

            if (!node.Type.IsValueType)
            {
                foreach (MemberAssignment assignment in node.Bindings)
                {
                    il.Dup();
                    context.EmitLoadArguments(assignment.Expression);
                    context.EmitMemberAssign(node.Type, assignment.Member);
                }
            }
            else
            {
                using (var temp = context.DeclareLocal(node.Type))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                    foreach (MemberAssignment assignment in node.Bindings)
                    {
                        il.Dup();
                        context.EmitLoadArguments(assignment.Expression);
                        context.EmitMemberAssign(node.Type, assignment.Member);
                    }
                    // todo или il.Ldobj()?
                    il.Pop();
                    il.Ldloc(temp);
                }
            }
            return(false);
        }
예제 #8
0
        public void GetReadILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local buffer, GroboIL.Local result, GroboIL.Local typeSize, GroboIL.Local offset, bool listValue)
        {
            var r = il.DeclareLocal(typeof(Vector3));

            if (listValue)
            {
                il.Ldloca(result);
            }
            else
            {
                il.Ldloca(r);
            }

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Call(readBitConverterMethodInfo);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldc_I4(4);
            il.Add();
            il.Call(readBitConverterMethodInfo);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldc_I4(8);
            il.Add();
            il.Call(readBitConverterMethodInfo);

            il.Call(initialConstructor);

            //if (listValue)
            //    il.Stloc(result);
            //else
            //    il.Stloc(r);

            BinaryStruct.WriteOffsetAppend(il, offset, 12);

            if (!listValue)
            {
                il.Ldloc(result);
                il.Ldloc(r);
                il.Call(prop.Setter, isVirtual: true);
            }
        }
        protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            if (node.Type != typeof(bool) && node.Type != typeof(bool?))
            {
                return(ExpressionEmittersCollection.Emit(Expression.OnesComplement(node.Operand, node.Method), context, returnDefaultValueLabel, whatReturn, extend, out resultType));
            }
            GroboIL il = context.Il;

            if (node.Method != null)
            {
                throw new NotSupportedException("Custom operator '" + node.NodeType + "' is not supported");
            }
            var operand = node.Operand;

            context.EmitLoadArgument(operand, false, out resultType);
            if (resultType == typeof(bool))
            {
                il.Ldc_I4(1);
                il.Xor();
            }
            else if (resultType == typeof(bool?))
            {
                using (var value = context.DeclareLocal(typeof(bool?)))
                {
                    il.Stloc(value);
                    il.Ldloca(value);
                    context.EmitHasValueAccess(typeof(bool?));
                    var returnLabel = il.DefineLabel("return");
                    il.Brfalse(returnLabel);
                    il.Ldloca(value);
                    context.EmitValueAccess(typeof(bool?));
                    il.Ldc_I4(1);
                    il.Xor();
                    il.Newobj(nullableBoolConstructor);
                    il.Stloc(value);
                    context.MarkLabelAndSurroundWithSP(returnLabel);
                    il.Ldloc(value);
                }
            }
            else
            {
                throw new InvalidOperationException("Cannot perform '" + node.NodeType + "' operator on type '" + resultType + "'");
            }
            return(false);
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            if (node.Conversion != null)
            {
                throw new NotSupportedException("Coalesce with conversion is not supported");
            }
            // note ich: баг решарпера
            // ReSharper disable HeuristicUnreachableCode
            var     left  = node.Left;
            var     right = node.Right;
            GroboIL il    = context.Il;

            GroboIL.Label valueIsNullLabel = il.DefineLabel("valueIsNull");
            Type          leftType;
            bool          labelUsed = ExpressionEmittersCollection.Emit(left, context, valueIsNullLabel, out leftType);

            if (left.Type.IsValueType)
            {
                using (var temp = context.DeclareLocal(left.Type))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                }
            }
            labelUsed |= context.EmitNullChecking(left.Type, valueIsNullLabel);
            if (left.Type.IsValueType)
            {
                if (!left.Type.IsNullable())
                {
                    throw new InvalidOperationException("Type '" + left.Type + "' cannot be null");
                }
                if (node.Type != left.Type)
                {
                    context.EmitValueAccess(left.Type);
                }
                else
                {
                    il.Ldobj(left.Type);
                }
            }
            var valueIsNotNullLabel = il.DefineLabel("valueIsNotNull");

            il.Br(valueIsNotNullLabel);
            if (labelUsed)
            {
                context.MarkLabelAndSurroundWithSP(valueIsNullLabel);
                il.Pop();
            }
            Type rightType;
            var  result = ExpressionEmittersCollection.Emit(right, context, returnDefaultValueLabel, out rightType);

            context.MarkLabelAndSurroundWithSP(valueIsNotNullLabel);
            resultType = node.Type;
            return(result);
            // ReSharper restore HeuristicUnreachableCode
        }
예제 #11
0
        public void GetReadILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local buffer, GroboIL.Local result, GroboIL.Local typeSize, GroboIL.Local offset, bool listValue)
        {
            var r = il.DeclareLocal(typeof(DateTime));
            var v = il.DeclareLocal(typeof(double));

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Call(readBitConverterMethodInfo);
            il.Stloc(v);

            il.Ldloca(r);
            il.Ldc_I4(1970);
            il.Ldc_I4(1);
            il.Ldc_I4(1);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Ldc_I4(0);
            il.Call(datetimeConstructor);

            il.Ldloca(r);
            il.Ldloc(v);
            il.Call(addMethod);

            if (listValue)
            {
                il.Stloc(result);
            }
            else
            {
                il.Stloc(r);
            }

            BinaryStruct.WriteOffsetAppend(il, offset, 8);
            if (!listValue)
            {
                il.Ldloc(result);
                il.Ldloc(r);
                il.Call(prop.Setter, isVirtual: true);
            }
        }
예제 #12
0
        private static EnumParserDelegate EmitEnumParser()
        {
            var method         = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(Type), typeof(string), typeof(bool) }, typeof(string), true);
            var il             = new GroboIL(method);
            var enumResultType = typeof(Enum).GetNestedType("EnumResult", BindingFlags.NonPublic);
            var enumResult     = il.DeclareLocal(enumResultType);

            il.Ldarg(0);
            il.Ldarg(1);
            il.Ldarg(2);
            il.Ldloca(enumResult);
            il.Call(typeof(Enum).GetMethod("TryParseEnum", BindingFlags.Static | BindingFlags.NonPublic));
            var returnNullLabel = il.DefineLabel("returnNull");

            il.Brfalse(returnNullLabel);
            il.Ldloca(enumResult);
            il.Ldfld(enumResultType.GetField("parsedEnum", BindingFlags.Instance | BindingFlags.NonPublic));
            il.Ret();
            il.MarkLabel(returnNullLabel);
            il.Ldnull();
            il.Ret();
            return((EnumParserDelegate)method.CreateDelegate(typeof(EnumParserDelegate)));
        }
        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();
            }
        }
예제 #14
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var ilValue = il.DeclareLocal(prop.PropertyInfo.PropertyType);

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(ilValue);

            var exitLabel = il.DefineLabel("exit");

            il.Ldloca(ilValue);
            BinaryStruct.WriteNullableType <TType>(il, exitLabel, buffer, offset);

            var nval = il.DeclareLocal(typeof(TType));

            il.Ldloca(ilValue);
            il.Call(Getter);
            il.Stloc(nval);

            (new T()).GetWriteILCode(prop, currentStruct, il, binaryStruct, nval, typeSize, buffer, offset, true);

            il.MarkLabel(exitLabel);
        }
예제 #15
0
        private static void EmitInstance(GroboIL il, MethodInfo getMethod, MethodInfo instanceMethod, GroboIL.Label returnFalse)
        {
            // a.Property.Equals(b.Property)
            var type  = getMethod.ReturnType;
            var local = il.DeclareLocal(type);

            il.Ldarg(0);
            il.Call(getMethod);
            il.Stloc(local);
            il.Ldloca(local);
            il.Ldarg(1);
            il.Call(getMethod);
            il.Call(instanceMethod, type);
            il.Brfalse(returnFalse);
        }
예제 #16
0
        private static void EmitNullableEquals(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
        {
            // a.Equals(b)
            var type  = getMethod.ReturnType;
            var local = il.DeclareLocal(type);

            il.Ldarg(0);
            il.Call(getMethod);
            il.Stloc(local);
            il.Ldloca(local);
            il.Ldarg(1);
            il.Call(getMethod);
            il.Box(type);
            il.Call(ObjectEquals, type);
            il.Brfalse(returnFalse);
        }
        protected override bool EmitInternal(TypeBinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            bool    result;
            GroboIL il = context.Il;

            if (!node.Expression.Type.IsAssignableFrom(node.TypeOperand))
            {
                il.Ldc_I4(0);
                result = false;
            }
            else if (node.Expression.Type == node.TypeOperand && node.TypeOperand.IsValueType)
            {
                il.Ldc_I4(1);
                result = false;
            }
            else
            {
                Type operandType;
                result = ExpressionEmittersCollection.Emit(node.Expression, context, returnDefaultValueLabel, ResultType.Value, extend, out operandType);
                if (operandType.IsValueType)
                {
                    using (var temp = context.DeclareLocal(operandType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                }
                var returnFalseLabel = il.DefineLabel("returnFalse");
                il.Dup();
                il.Brfalse(returnFalseLabel);
                il.Call(typeof(object).GetMethod("GetType"), operandType);
                il.Ldtoken(node.TypeOperand);
                il.Call(typeof(Type).GetMethod("GetTypeFromHandle"));
                il.Ceq();
                var doneLabel = il.DefineLabel("done");
                il.Br(doneLabel);
                context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                il.Pop();
                il.Ldc_I4(0);
                context.MarkLabelAndSurroundWithSP(doneLabel);
            }
            resultType = typeof(bool);
            return(result);
        }
예제 #18
0
        public const int Seed = 314159265; //NOTE не менять !!!

        private static Func <DynamicMethod, IntPtr> EmitDynamicMethodPointerExtractor()
        {
            if (PlatformHelpers.IsMono)
            {
                return(dynMethod =>
                {
                    var handle = dynMethod.MethodHandle;
                    RuntimeHelpers.PrepareMethod(handle);
                    return handle.GetFunctionPointer();
                });
            }
            var method = new DynamicMethod("DynamicMethodPointerExtractor", typeof(IntPtr), new[] { typeof(DynamicMethod) }, typeof(GroBufHelpers).Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [dynamicMethod]
                MethodInfo getMethodDescriptorMethod = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.Instance | BindingFlags.NonPublic);
                if (getMethodDescriptorMethod == null)
                {
                    throw new MissingMethodException(typeof(DynamicMethod).Name, "GetMethodDescriptor");
                }
                il.Call(getMethodDescriptorMethod); // stack: [dynamicMethod.GetMethodDescriptor()]
                var runtimeMethodHandle = il.DeclareLocal(typeof(RuntimeMethodHandle));
                il.Stloc(runtimeMethodHandle);      // runtimeMethodHandle = dynamicMethod.GetMethodDescriptor(); stack: []
                il.Ldloc(runtimeMethodHandle);      // stack: [runtimeMethodHandle]
                MethodInfo prepareMethodMethod = typeof(RuntimeHelpers).GetMethod("PrepareMethod", new[] { typeof(RuntimeMethodHandle) });
                if (prepareMethodMethod == null)
                {
                    throw new MissingMethodException(typeof(RuntimeHelpers).Name, "PrepareMethod");
                }
                il.Call(prepareMethodMethod); // RuntimeHelpers.PrepareMethod(runtimeMethodHandle)
                MethodInfo getFunctionPointerMethod = typeof(RuntimeMethodHandle).GetMethod("GetFunctionPointer", BindingFlags.Instance | BindingFlags.Public);
                if (getFunctionPointerMethod == null)
                {
                    throw new MissingMethodException(typeof(RuntimeMethodHandle).Name, "GetFunctionPointer");
                }
                il.Ldloca(runtimeMethodHandle);    // stack: [&runtimeMethodHandle]
                il.Call(getFunctionPointerMethod); // stack: [runtimeMethodHandle.GetFunctionPointer()]
                il.Ret();                          // return runtimeMethodHandle.GetFunctionPointer()
            }
            return((Func <DynamicMethod, IntPtr>)method.CreateDelegate(typeof(Func <DynamicMethod, IntPtr>)));
        }
예제 #19
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);

            var exitLabel = il.DefineLabel("exit");

            BinaryStruct.WriteSizeChecker(il, buffer, offset, 5);
            BinaryStruct.WriteObjectNull(il, exitLabel, arr, buffer, offset, typeSize);

            var arrSize = il.DeclareLocal(typeof(byte[]));
            var len     = il.DeclareLocal(typeof(int));

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Call(typeof(ICollection).GetProperty("Count").GetMethod);
            il.Stloc(len);

            il.Ldloc(len);
            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arrSize);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arrSize);
            il.Ldc_I4(0);
            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            for (int i = 1; i < 4; i++)
            {
                il.Ldloc(buffer);
                il.Ldloc(offset);
                il.Ldc_I4(i);
                il.Add();
                il.Ldloc(arrSize);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }

            BinaryStruct.WriteOffsetAppend(il, offset, 4);


            il.Ldloc(len);
            il.Ldc_I4(0);
            il.Ceq();
            il.Brtrue(exitLabel);

            var typeKey   = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];
            var typeValue = prop.PropertyInfo.PropertyType.GetGenericArguments()[1];

            var ivar             = il.DeclareLocal(typeof(int));
            var currentItemKey   = il.DeclareLocal(typeKey);
            var currentItemValue = il.DeclareLocal(typeValue);

            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            var enumeratorMethod = prop.PropertyInfo.PropertyType.GetMethod("GetEnumerator");

            var enumerator = il.DeclareLocal(enumeratorMethod.ReturnType);

            var moveNext   = typeof(IEnumerator).GetMethod("MoveNext");
            var getCurrent = enumerator.Type.GetMethod("get_Current");

            var temp  = il.DeclareLocal(getCurrent.ReturnType);
            var exist = il.DeclareLocal(typeof(bool));

            il.Ldloc(arr);
            il.Call(enumeratorMethod, isVirtual: true);
            il.Stloc(enumerator);

            var keyGetter   = getCurrent.ReturnType.GetMethod("get_Key");
            var valueGetter = getCurrent.ReturnType.GetMethod("get_Value");

            il.MarkLabel(point);

            //body

            il.Ldloc(enumerator);
            il.Call(moveNext);
            il.Stloc(exist);

            il.Ldloc(enumerator);
            il.Call(getCurrent, enumerator.Type);
            il.Stloc(temp);

            il.Ldloca(temp);
            il.Call(keyGetter, typeof(int));
            il.Stloc(currentItemKey);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemKey, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeKey, currentStruct.Scheme), il, binaryStruct, currentItemKey, buffer, offset, typeSize);
            }

            il.Ldloca(temp);
            il.Call(valueGetter);
            il.Stloc(currentItemValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[1]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[1]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeValue, currentStruct.Scheme), il, binaryStruct, currentItemValue, buffer, offset, typeSize);
            }
            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);


            il.MarkLabel(exitLabel);
        }
예제 #20
0
        public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext)
        {
            var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, readerTypeBuilderContext.Module, true);

            readerTypeBuilderContext.SetReaderMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference);

                ReadTypeCodeAndCheck(context); // Read TypeCode and check

                if (!Type.IsValueType && IsReference)
                {
                    // Read reference
                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    var notReadLabel = il.DefineLabel("notRead");
                    il.Brfalse(notReadLabel);
                    context.LoadIndex();                  // stack: [external index]
                    context.LoadContext();                // stack: [external index, context]
                    il.Ldfld(ReaderContext.StartField);   // stack: [external index, context.start]
                    il.Sub();                             // stack: [external index - context.start]
                    il.Stloc(context.Index);              // index = external index - context.start; stack: []

                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    il.Ldloc(context.Index);              // stack: [context.objects, index]
                    var obj = il.DeclareLocal(typeof(object));
                    il.Ldloca(obj);
                    object dummy;
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)]
                    il.Brfalse(notReadLabel);                                                                                     // if(!context.objects.TryGetValue(index, out obj)) goto notRead;
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    context.IncreaseIndexBy1();                                                                                   // Skip type code
                    context.SkipValue();                                                                                          // Skip value - it has already been read
                    il.Ret();
                    il.MarkLabel(notReadLabel);
                    il.Ldloc(context.TypeCode);               // stack: [typeCode]
                    il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference]
                    var readUsualLabel = il.DefineLabel("readUsual");
                    il.Bne_Un(readUsualLabel);                // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: []

                    context.LoadContext();                    // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);     // stack: [context.objects]
                    var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull");
                    il.Brtrue(objectsIsNotNullLabel);         // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects]
                    il.Ldstr("Reference is not valid at this point");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(objectsIsNotNullLabel);

                    context.IncreaseIndexBy1(); // index = index + 1; stack: []
                    il.Ldc_I4(4);
                    context.AssertLength();
                    context.GoToCurrentLocation();
                    var reference = il.DeclareLocal(typeof(int));
                    il.Ldind(typeof(int));             // stack: [*(int*)data[index]]
                    il.Stloc(reference);               // reference = *(int*)data[index]; stack: []
                    context.IncreaseIndexBy4();        // index = index + 4; stack: []
                    il.Ldloc(context.Index);           // stack: [index]
                    il.Ldloc(reference);               // stack: [index, reference]
                    var goodReferenceLabel = il.DefineLabel("goodReference");
                    il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: []
                    il.Ldstr("Bad reference");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(goodReferenceLabel);
                    context.LoadContext();                                                                                        // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);                                                                         // stack: [context.objects]
                    il.Ldloc(reference);                                                                                          // stack: [context.objects, reference]
                    il.Ldloca(obj);                                                                                               // stack: [context.objects, reference, ref obj]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)]
                    var readObjectLabel = il.DefineLabel("readObject");
                    il.Brfalse(readObjectLabel);                                                                                  // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: []
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    il.Ret();
                    il.MarkLabel(readObjectLabel);

                    // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted
                    context.LoadData();                 // stack: [data]
                    il.Ldloc(reference);                // stack: [data, reference]
                    context.LoadContext();              // stack: [data, reference, context]
                    il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start]
                    il.Add();                           // stack: [data, reference + context.start]
                    il.Stloc(reference);                // reference += context.start; stack: [data]
                    il.Ldloca(reference);               // stack: [data, ref reference]
                    context.LoadResultByRef();          // stack: [data, ref reference, ref result]
                    context.LoadContext();              // stack: [data, ref reference, ref result, context]
                    context.CallReader(Type);
                    il.Ret();
                    il.MarkLabel(readUsualLabel);
                }

                ReadNotEmpty(context); // Read obj
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate);
        }
예제 #21
0
        private static void EmitNullableBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
        {
            // a.GetValueOrDefault() == b.GetValueOrDefault() && a.HasValue == b.HasValue;
            var type = getMethod.ReturnType;
            var getValueOrDefault = type.GetMethod("GetValueOrDefault", new Type[0]);
            var hasValue = type.GetMethod("get_HasValue");
            var a = il.DeclareLocal(type);
            var b = il.DeclareLocal(type);

            il.Ldarg(0);
            il.Call(getMethod);
            il.Stloc(a);
            il.Ldarg(1);
            il.Call(getMethod);
            il.Stloc(b);

            il.Ldloca(a);
            il.Call(getValueOrDefault);
            il.Ldloca(b);
            il.Call(getValueOrDefault);
            il.Bne_Un(returnFalse);

            il.Ldloca(a);
            il.Call(hasValue);
            il.Ldloca(b);
            il.Call(hasValue);
            il.Bne_Un(returnFalse);
        }
        protected override bool EmitInternal(SwitchExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL il           = context.Il;
            var     defaultLabel = il.DefineLabel("default");
            var     caseLabels   = new GroboIL.Label[node.Cases.Count];

            GroboIL.Label switchValueIsNullLabel = null;
            for (int index = 0; index < node.Cases.Count; index++)
            {
                caseLabels[index] = il.DefineLabel("case#" + index);
            }
            context.EmitLoadArguments(node.SwitchValue);
            using (var switchValue = context.DeclareLocal(node.SwitchValue.Type))
            {
                il.Stloc(switchValue);
                Tuple <int, int, int> switchCase;
                if (context.ParsedLambda.ParsedSwitches.TryGetValue(node, out switchCase))
                {
                    // use simplified hashtable to locate the proper case
                    var labels = new List <GroboIL.Label>();
                    for (int index = 0; index < node.Cases.Count; index++)
                    {
                        foreach (var testValue in node.Cases[index].TestValues)
                        {
                            if (((ConstantExpression)testValue).Value != null)
                            {
                                labels.Add(caseLabels[index]);
                            }
                            else
                            {
                                switchValueIsNullLabel = caseLabels[index];
                            }
                        }
                    }
                    if (switchValueIsNullLabel != null)
                    {
                        if (!node.SwitchValue.Type.IsNullable())
                        {
                            il.Ldloc(switchValue);
                        }
                        else
                        {
                            il.Ldloca(switchValue);
                            context.EmitHasValueAccess(node.SwitchValue.Type);
                        }
                        il.Brfalse(switchValueIsNullLabel);
                    }
                    EmittingContext.LocalHolder pureSwitchValue = switchValue;
                    if (node.SwitchValue.Type.IsNullable())
                    {
                        pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]);
                        il.Ldloca(switchValue);
                        context.EmitValueAccess(node.SwitchValue.Type);
                        il.Stloc(pureSwitchValue);
                    }
                    Type temp;
                    ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item1), context, out temp);
                    var type     = node.SwitchValue.Type.IsNullable() ? node.SwitchValue.Type.GetGenericArguments()[0] : node.SwitchValue.Type;
                    var typeCode = Type.GetTypeCode(type);
                    switch (typeCode)
                    {
                    case TypeCode.Byte:
                    case TypeCode.Char:
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                    case TypeCode.SByte:
                    case TypeCode.UInt16:
                    case TypeCode.UInt32:
                    case TypeCode.UInt64:
                        il.Ldloc(pureSwitchValue);
                        break;

                    default:
                        if (type.IsValueType)
                        {
                            il.Ldloca(pureSwitchValue);
                        }
                        else
                        {
                            il.Ldloc(pureSwitchValue);
                        }
                        il.Call(typeof(object).GetMethod("GetHashCode"), type);
                        break;
                    }
                    using (var index = context.DeclareLocal(typeof(int)))
                    {
                        if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64)
                        {
                            il.Ldc_I8(switchCase.Item3);
                        }
                        else
                        {
                            il.Ldc_I4(switchCase.Item3);
                        }
                        il.Rem(true);
                        if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64)
                        {
                            il.Conv <int>();
                        }
                        il.Stloc(index);
                        il.Ldloc(index);
                        il.Ldelem(type);
                        il.Ldloc(pureSwitchValue);
                        if (node.Comparison != null)
                        {
                            il.Call(node.Comparison);
                        }
                        else
                        {
                            il.Ceq();
                        }
                        il.Brfalse(defaultLabel);
                        ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item2), context, out temp);
                        il.Ldloc(index);
                        il.Ldelem(typeof(int));
                        il.Switch(labels.ToArray());
                    }
                    if (pureSwitchValue != switchValue)
                    {
                        pureSwitchValue.Dispose();
                    }
                }
                else
                {
                    // use a number of if/else branches to locate the proper case
                    EmittingContext.LocalHolder pureSwitchValue   = switchValue;
                    EmittingContext.LocalHolder switchValueIsNull = null;
                    if (node.SwitchValue.Type.IsNullable())
                    {
                        pureSwitchValue   = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]);
                        switchValueIsNull = context.DeclareLocal(typeof(bool));
                        il.Ldloca(switchValue);
                        il.Dup();
                        context.EmitValueAccess(node.SwitchValue.Type);
                        il.Stloc(pureSwitchValue);
                        context.EmitHasValueAccess(node.SwitchValue.Type);
                        il.Stloc(switchValueIsNull);
                    }
                    for (int index = 0; index < node.Cases.Count; index++)
                    {
                        var caSe  = node.Cases[index];
                        var label = caseLabels[index];
                        foreach (var testValue in caSe.TestValues)
                        {
                            context.EmitLoadArguments(testValue);
                            GroboIL.Label elseLabel = null;
                            if (testValue.Type.IsNullable())
                            {
                                elseLabel = il.DefineLabel("else");
                                using (var temp = context.DeclareLocal(testValue.Type))
                                {
                                    il.Stloc(temp);
                                    il.Ldloca(temp);
                                    context.EmitHasValueAccess(testValue.Type);
                                    if (switchValueIsNull != null)
                                    {
                                        il.Ldloc(switchValueIsNull);
                                        il.Or();
                                        il.Brfalse(label);
                                        il.Ldloca(temp);
                                        context.EmitHasValueAccess(testValue.Type);
                                        il.Ldloc(switchValueIsNull);
                                        il.And();
                                    }
                                    il.Brfalse(elseLabel);
                                    il.Ldloca(temp);
                                    context.EmitValueAccess(testValue.Type);
                                }
                            }
                            il.Ldloc(pureSwitchValue);
                            if (node.Comparison != null)
                            {
                                il.Call(node.Comparison);
                            }
                            else
                            {
                                il.Ceq();
                            }
                            il.Brtrue(label);
                            if (elseLabel != null)
                            {
                                context.MarkLabelAndSurroundWithSP(elseLabel);
                            }
                        }
                    }
                }
            }
            context.MarkLabelAndSurroundWithSP(defaultLabel);
            var doneLabel = il.DefineLabel("done");

            context.EmitLoadArguments(node.DefaultBody);
            il.Br(doneLabel);
            for (int index = 0; index < node.Cases.Count; ++index)
            {
                context.MarkLabelAndSurroundWithSP(caseLabels[index]);
                context.EmitLoadArguments(node.Cases[index].Body);
                if (index < node.Cases.Count - 1)
                {
                    il.Br(doneLabel);
                }
            }
            context.MarkLabelAndSurroundWithSP(doneLabel);
            resultType = node.Type;
            return(false);
        }
        protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL      il      = context.Il;
            var          result  = false;
            var          operand = node.Operand;
            Type         assigneeType;
            AssigneeKind assigneeKind;
            bool         checkNullReferences = context.Options.HasFlag(CompilerOptions.CheckNullReferences);

            extend |= context.Options.HasFlag(CompilerOptions.ExtendOnAssign);

            GroboIL.Label assigneeIsNullLabel     = null;
            bool          assigneeIsNullLabelUsed = false;

            switch (operand.NodeType)
            {
            case ExpressionType.Parameter:
                assigneeType        = null;
                assigneeKind        = AssigneeKind.Parameter;
                checkNullReferences = false;
                break;

            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression)operand;
                if (memberExpression.Expression == null)
                {
                    assigneeType        = null;
                    assigneeKind        = memberExpression.Member is FieldInfo ? AssigneeKind.StaticField : AssigneeKind.StaticProperty;
                    checkNullReferences = false;
                }
                else
                {
                    bool closureAssign = memberExpression.Expression == context.ParsedLambda.ClosureParameter || memberExpression.Expression.Type.IsStaticClosure();
                    checkNullReferences &= !closureAssign;
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(memberExpression.Expression, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = !closureAssign && context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(memberExpression.Expression, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = memberExpression.Member is FieldInfo ? AssigneeKind.InstanceField : AssigneeKind.InstanceProperty;
                }
                break;

            case ExpressionType.Index:
                var indexExpression = (IndexExpression)operand;
                if (indexExpression.Object == null)
                {
                    throw new InvalidOperationException("Indexing of null object is invalid");
                }
                if (indexExpression.Object.Type.IsArray && indexExpression.Object.Type.GetArrayRank() == 1)
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, returnDefaultValueLabel, ResultType.ByRefAll, extend, out assigneeType);
                        checkNullReferences = false;
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, assigneeIsNullLabel, ResultType.ByRefAll, extend, out assigneeType);
                    }
                    assigneeKind = AssigneeKind.SimpleArray;
                }
                else
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(indexExpression.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(indexExpression.Object, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = indexExpression.Indexer != null ? AssigneeKind.IndexedProperty : AssigneeKind.MultiDimensionalArray;
                }
                break;

            default:
                throw new InvalidOperationException("Unable to assign to an expression of type '" + operand.NodeType + "'");
            }
            if (assigneeType != null && assigneeType.IsValueType)
            {
                using (var temp = context.DeclareLocal(assigneeType))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                }
                assigneeType = assigneeType.MakeByRefType();
            }
            if (assigneeIsNullLabelUsed)
            {
                context.EmitReturnDefaultValue(assigneeType, assigneeIsNullLabel, il.DefineLabel("assigneeIsNotNull"));
            }

            if (checkNullReferences)
            {
                il.Dup();
                il.Brfalse(returnDefaultValueLabel);
                result = true;
            }

            if (assigneeType != null)
            {
                il.Dup();
            }
            object[] arguments = EmitAccess(assigneeKind, operand, context);
            if (!operand.Type.IsNullable())
            {
                if (whatReturn == ResultType.Void)
                {
                    EmitOp(node.NodeType, node.Method, node.Type, context);
                    EmitAssign(assigneeKind, operand, context, arguments);
                }
                else
                {
                    if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign)
                    {
                        using (var assignmentResult = context.DeclareLocal(operand.Type))
                        {
                            il.Stloc(assignmentResult);
                            il.Ldloc(assignmentResult);
                            EmitOp(node.NodeType, node.Method, node.Type, context);
                            EmitAssign(assigneeKind, operand, context, arguments);
                            il.Ldloc(assignmentResult);
                        }
                    }
                    else
                    {
                        EmitOp(node.NodeType, node.Method, node.Type, context);
                        using (var assignmentResult = context.DeclareLocal(operand.Type))
                        {
                            il.Stloc(assignmentResult);
                            EmitAssign(assigneeKind, operand, context, arguments, assignmentResult);
                            il.Ldloc(assignmentResult);
                        }
                    }
                }
            }
            else
            {
                using (var value = context.DeclareLocal(operand.Type))
                {
                    il.Stloc(value);
                    il.Ldloca(value);
                    context.EmitHasValueAccess(operand.Type);
                    var returnNullLabel = il.DefineLabel("returnNull");
                    il.Brfalse(returnNullLabel);
                    il.Ldloca(value);
                    context.EmitValueAccess(operand.Type);
                    Type            argumentType = operand.Type.GetGenericArguments()[0];
                    ConstructorInfo constructor  = operand.Type.GetConstructor(new[] { argumentType });
                    if (whatReturn == ResultType.Void)
                    {
                        EmitOp(node.NodeType, node.Method, argumentType, context);
                        il.Newobj(constructor);
                        EmitAssign(assigneeKind, operand, context, arguments);
                    }
                    else
                    {
                        if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign)
                        {
                            EmitOp(node.NodeType, node.Method, argumentType, context);
                            il.Newobj(constructor);
                            EmitAssign(assigneeKind, operand, context, arguments);
                            il.Ldloc(value);
                        }
                        else
                        {
                            EmitOp(node.NodeType, node.Method, argumentType, context);
                            il.Newobj(constructor);
                            using (var assignmentResult = context.DeclareLocal(operand.Type))
                            {
                                il.Stloc(assignmentResult);
                                EmitAssign(assigneeKind, operand, context, arguments, assignmentResult);
                                il.Ldloc(assignmentResult);
                            }
                        }
                    }
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);
                    context.MarkLabelAndSurroundWithSP(returnNullLabel);
                    if (assigneeType != null)
                    {
                        il.Pop();
                    }
                    if (whatReturn != ResultType.Void)
                    {
                        il.Ldloc(value);
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                }
            }
            resultType = whatReturn == ResultType.Void ? typeof(void) : operand.Type;
            return(result);
        }
예제 #24
0
 private static void EmitNullableEquals(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
 {
     // a.Equals(b)
     var type = getMethod.ReturnType;
     var local = il.DeclareLocal(type);
     il.Ldarg(0);
     il.Call(getMethod);
     il.Stloc(local);
     il.Ldloca(local);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Box(type);
     il.Call(ObjectEquals, type);
     il.Brfalse(returnFalse);
 }
예제 #25
0
        private KeyValuePair <Delegate, IntPtr> GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member)
        {
            var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [data]
                il.Ldarg(1); // stack: [data, ref index]
                switch (member.MemberType)
                {
                case MemberTypes.Field:
                    var field = (FieldInfo)member;
                    var done  = false;
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType)
                    {
                        var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (field.FieldType.IsPrimitive || equalityOperator != null)
                        {
                            var fieldValue = il.DeclareLocal(field.FieldType);
                            il.Ldarg(2); // stack: [data, ref index, ref result]
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldfld(field);
                            il.Stloc(fieldValue);
                            il.Ldloca(fieldValue);
                            il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                            ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []

                            var temp = il.DeclareLocal(field.FieldType);
                            il.Ldloca(temp);
                            il.Initobj(field.FieldType);
                            il.Ldloc(temp);
                            il.Ldloc(fieldValue);
                            if (field.FieldType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                            il.Ldarg(2);
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldloc(fieldValue);
                            il.Stfld(field);
                            done = true;
                        }
                    }
                    if (!done)
                    {
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                  // stack: [data, ref index, result]
                        }
                        il.Ldflda(field);                                                    // stack: [data, ref index, ref result.field]
                        il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                        ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []
                    }
                    break;

                case MemberTypes.Property:
                    var property      = (PropertyInfo)member;
                    var propertyValue = il.DeclareLocal(property.PropertyType);
                    if (context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead))
                    {
                        var getter = property.GetGetMethod(true);
                        if (getter == null)
                        {
                            throw new MissingMethodException(Type.Name, property.Name + "_get");
                        }
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                    // stack: [data, ref index, result]
                        }
                        il.Call(getter, Type);                                                 // stack: [ data, ref index, result.property]
                        il.Stloc(propertyValue);                                               // propertyValue = result.property; stack: [data, ref index]
                    }
                    il.Ldloca(propertyValue);                                                  // stack: [data, ref index, ref propertyValue]
                    il.Ldarg(3);                                                               // stack: [data, ref index, ref propertyValue, context]
                    ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: []
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType)
                    {
                        var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (property.PropertyType.IsPrimitive || equalityOperator != null)
                        {
                            var temp = il.DeclareLocal(property.PropertyType);
                            il.Ldloca(temp);
                            il.Initobj(property.PropertyType);
                            il.Ldloc(temp);
                            il.Ldloc(propertyValue);
                            if (property.PropertyType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                        }
                    }
                    il.Ldarg(2); // stack: [ref result]
                    if (!Type.IsValueType)
                    {
                        il.Ldind(Type);      // stack: [result]
                    }
                    il.Ldloc(propertyValue); // stack: [result, propertyValue]
                    var setter = property.GetSetMethod(true);
                    if (setter == null)
                    {
                        throw new MissingMethodException(Type.Name, property.Name + "_set");
                    }
                    il.Call(setter, Type); // result.property = propertyValue
                    break;

                default:
                    throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported");
                }
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
예제 #26
0
        protected override bool EmitInternal(MethodCallExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var        result = false;
            GroboIL    il     = context.Il;
            var        method = node.Method;
            Expression obj;
            IEnumerable <Expression>    arguments;
            IEnumerable <ParameterInfo> parameters;
            bool isStatic = method.IsStatic;

            if (!isStatic)
            {
                obj        = node.Object;
                arguments  = node.Arguments;
                parameters = method.GetParameters();
            }
            else if (method.DeclaringType == typeof(Enumerable))
            {
                obj        = node.Arguments[0];
                arguments  = node.Arguments.Skip(1);
                parameters = method.GetParameters().Skip(1);
            }
            else
            {
                obj        = null;
                arguments  = node.Arguments;
                parameters = method.GetParameters();
            }
            Type type = obj == null ? null : obj.Type;

            if (obj != null)
            {
                Type actualType;
                result |= ExpressionEmittersCollection.Emit(obj, context, returnDefaultValueLabel, isStatic ? ResultType.Value : ResultType.ByRefValueTypesOnly, extend, out actualType); // stack: [obj]
                if (actualType == typeof(void))
                {
                    throw new InvalidOperationException("Unable to call method on void");
                }
                if (actualType.IsValueType && !isStatic)
                {
                    using (var temp = context.DeclareLocal(actualType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                    actualType = actualType.MakeByRefType();
                }
                if (context.Options.HasFlag(CompilerOptions.CheckNullReferences) && !actualType.IsValueType)
                {
                    if (method.DeclaringType != typeof(Enumerable))
                    {
                        result |= context.EmitNullChecking(type, returnDefaultValueLabel);
                    }
                    else
                    {
                        var arrIsNotNullLabel = il.DefineLabel("arrIsNotNull");
                        il.Dup();
                        il.Brtrue(arrIsNotNullLabel);
                        il.Pop();
                        il.Ldc_I4(0);
                        il.Newarr(GetElementType(type));
                        context.MarkLabelAndSurroundWithSP(arrIsNotNullLabel);
                    }
                }
            }

            var parametersArray = parameters.ToArray();
            var argumentsArray  = arguments.ToArray();

            for (int i = 0; i < argumentsArray.Length; i++)
            {
                var argument  = argumentsArray[i];
                var parameter = parametersArray[i];
                if (parameter.ParameterType.IsByRef)
                {
                    Type argumentType;
                    var  options = context.Options;
                    context.Options = CompilerOptions.None;
                    ExpressionEmittersCollection.Emit(argument, context, null, ResultType.ByRefAll, false, out argumentType);
                    context.Options = options;
                    if (!argumentType.IsByRef)
                    {
                        throw new InvalidOperationException("Expected type by reference");
                    }
                }
                else
                {
                    Type argumentType;
                    context.EmitLoadArgument(argument, true, out argumentType);
                }
            }
            il.Call(method, type);
            resultType = node.Type;
            return(result);
        }
예제 #27
0
        private KeyValuePair <Delegate, IntPtr> BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode)
        {
            var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true);

            using (var il = new GroboIL(method))
            {
                var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type);

                il.Ldarg(1); // stack: [ref result]
                if (typeCode == GroBufTypeCode.Decimal)
                {
                    if (expectedTypeCode == GroBufTypeCode.Boolean)
                    {
                        il.Ldarg(0);            // stack: [ref result, &temp, address]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address]
                        il.Ldarg(0);            // stack: [ref result, &temp + 8, address]
                        il.Ldc_I4(8);           // stack: [ref result, &temp + 8, address, 8]
                        il.Add();               // stack: [ref result, &temp + 8, address + 8]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)]
                        il.Or();
                        il.Ldc_I4(0);           // stack: [ref result, value, 0]
                        il.Conv <long>();
                        il.Ceq();               // stack: [ref result, value == 0]
                        il.Ldc_I4(1);           // stack: [ref result, value == 0, 1]
                        il.Xor();               // stack: [ref result, value != 0]
                    }
                    else
                    {
                        var temp = il.DeclareLocal(typeof(decimal));
                        il.Ldloca(temp);        // stack: [ref result, &temp]
                        il.Ldarg(0);            // stack: [ref result, &temp, address]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address]
                        il.Stind(typeof(long)); // *temp = *address;
                        il.Ldloca(temp);        // stack: [ref result, &temp]
                        il.Ldc_I4(8);           // stack: [ref result, &temp, 8]
                        il.Add();               // stack: [ref result, &temp + 8]
                        il.Ldarg(0);            // stack: [ref result, &temp + 8, address]
                        il.Ldc_I4(8);           // stack: [ref result, &temp + 8, address, 8]
                        il.Add();               // stack: [ref result, &temp + 8, address + 8]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)]
                        il.Stind(typeof(long)); // *(temp + 8) = *(address + 8);

                        il.Ldloc(temp);         // stack: [ref result, ref temp]
                        switch (expectedTypeCode)
                        {
                        case GroBufTypeCode.Int8:
                            il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp]
                            break;

                        case GroBufTypeCode.UInt8:
                            il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp]
                            break;

                        case GroBufTypeCode.Int16:
                            il.Call(decimalToInt16Method); // stack: [ref result, (short)temp]
                            break;

                        case GroBufTypeCode.UInt16:
                            il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp]
                            break;

                        case GroBufTypeCode.Int32:
                            il.Call(decimalToInt32Method); // stack: [ref result, (int)temp]
                            break;

                        case GroBufTypeCode.UInt32:
                            il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp]
                            break;

                        case GroBufTypeCode.Int64:
                            il.Call(decimalToInt64Method); // stack: [ref result, (long)temp]
                            break;

                        case GroBufTypeCode.UInt64:
                            il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp]
                            break;

                        case GroBufTypeCode.Single:
                            il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp]
                            break;

                        case GroBufTypeCode.Double:
                            il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp]
                            break;

                        case GroBufTypeCode.Decimal:
                            break;

                        default:
                            throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported");
                        }
                    }
                }
                else
                {
                    il.Ldarg(0);                                                                                // stack: [ref result, address]
                    EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value]
                    if (Type == typeof(bool))
                    {
                        il.Conv <long>();
                        il.Ldc_I4(0); // stack: [ref result, value, 0]
                        il.Conv <long>();
                        il.Ceq();     // stack: [ref result, value == 0]
                        il.Ldc_I4(1); // stack: [ref result, value == 0, 1]
                        il.Xor();     // stack: [ref result, value != 0]
                    }
                    else
                    {
                        EmitConvertValue(il, typeCode, expectedTypeCode);
                    }
                }
                switch (expectedTypeCode)
                {
                case GroBufTypeCode.Int8:
                case GroBufTypeCode.UInt8:
                case GroBufTypeCode.Boolean:
                    il.Stind(typeof(byte)); // result = value
                    break;

                case GroBufTypeCode.Int16:
                case GroBufTypeCode.UInt16:
                    il.Stind(typeof(short)); // result = value
                    break;

                case GroBufTypeCode.Int32:
                case GroBufTypeCode.UInt32:
                    il.Stind(typeof(int)); // result = value
                    break;

                case GroBufTypeCode.Int64:
                case GroBufTypeCode.UInt64:
                    il.Stind(typeof(long)); // result = value
                    break;

                case GroBufTypeCode.Single:
                    il.Stind(typeof(float)); // result = value
                    break;

                case GroBufTypeCode.Double:
                    il.Stind(typeof(double)); // result = value
                    break;

                case GroBufTypeCode.Decimal:
                    il.Stobj(typeof(decimal)); // result = value
                    break;

                default:
                    throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported");
                }
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
예제 #28
0
 private static void EmitInstance(GroboIL il, MethodInfo getMethod, MethodInfo instanceMethod, GroboIL.Label returnFalse)
 {
     // a.Property.Equals(b.Property)
     var type = getMethod.ReturnType;
     var local = il.DeclareLocal(type);
     il.Ldarg(0);
     il.Call(getMethod);
     il.Stloc(local);
     il.Ldloca(local);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Call(instanceMethod, type);
     il.Brfalse(returnFalse);
 }
        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.");
            }
        }
예제 #30
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);
            var len = il.DeclareLocal(typeof(int));

            if (prop.PropertyInfo != null)
            {
                il.Ldloc(value);
                il.Call(prop.ArraySizeProperty.Getter);
                il.Stloc(len);
            }
            else
            {
                il.Ldc_I4(prop.ArraySize);
                il.Stloc(len);
            }

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);

            var typeKey   = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];
            var typeValue = prop.PropertyInfo.PropertyType.GetGenericArguments()[1];

            var ivar             = il.DeclareLocal(typeof(int));
            var currentItemKey   = il.DeclareLocal(typeKey);
            var currentItemValue = il.DeclareLocal(typeValue);

            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            var enumeratorMethod = prop.PropertyInfo.PropertyType.GetMethod("GetEnumerator");

            var enumerator = il.DeclareLocal(enumeratorMethod.ReturnType);

            var moveNext   = enumerator.Type.GetMethod("MoveNext");
            var getCurrent = enumerator.Type.GetMethod("get_Current");

            var temp  = il.DeclareLocal(getCurrent.ReturnType);
            var exist = il.DeclareLocal(typeof(bool));

            il.Ldloc(arr);
            il.Call(enumeratorMethod, isVirtual: true);
            il.Stloc(enumerator);

            var keyGetter   = getCurrent.ReturnType.GetMethod("get_Key");
            var valueGetter = getCurrent.ReturnType.GetMethod("get_Value");

            il.MarkLabel(point);

            //body

            il.Ldloca(enumerator);
            il.Call(moveNext, enumerator.Type);
            il.Stloc(exist);

            il.Ldloca(enumerator);
            //il.Calli(CallingConventions.Any, typeof(KeyValuePair<int, int>),new Type[] { typeof(int),typeof(int) });
            il.Call(getCurrent, enumerator.Type);
            il.Stloc(temp);

            il.Ldloca(temp);
            il.Call(keyGetter, typeof(int));
            il.Stloc(currentItemKey);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemKey, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeKey, currentStruct.Scheme), il, binaryStruct, currentItemKey, buffer, offset, typeSize);
            }

            il.Ldloca(temp);
            il.Call(valueGetter);
            il.Stloc(currentItemValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[1]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[1]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeValue, currentStruct.Scheme), il, binaryStruct, currentItemValue, buffer, offset, typeSize);
            }
            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);
        }
예제 #31
0
        public bool EmitMemberAccess(MemberExpression node, GroboIL.Label returnDefaultValueLabel, bool checkNullReferences, bool extend, ResultType whatReturn, out Type resultType, out LocalHolder owner)
        {
            bool result = false;

            owner = null;
            Type    type = node.Expression == null ? null : node.Expression.Type;
            Type    ownerType;
            GroboIL il = Il;

            if (node.Expression == null)
            {
                ownerType = null;
            }
            else
            {
                result |= ExpressionEmittersCollection.Emit(node.Expression, this, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out type); // stack: [obj]
                if (!type.IsValueType)
                {
                    ownerType = type;
                }
                else
                {
                    ownerType = type.MakeByRefType();
                    using (var temp = DeclareLocal(type))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                }
                if (checkNullReferences && node.Expression != ParsedLambda.ClosureParameter && node.Expression != ParsedLambda.ConstantsParameter && !node.Expression.Type.IsStaticClosure())
                {
                    result |= EmitNullChecking(node.Expression.Type, returnDefaultValueLabel);
                }
            }
            extend &= CanAssign(node.Member);
            Type            memberType  = GetMemberType(node.Member);
            ConstructorInfo constructor = memberType.GetConstructor(Type.EmptyTypes);

            extend &= (memberType.IsClass && constructor != null) || memberType.IsArray;
            if (!extend)
            {
                EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
            }
            else
            {
                if (node.Expression == null)
                {
                    EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
                    var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull");
                    il.Dup();
                    il.Brtrue(memberIsNotNullLabel);
                    il.Pop();
                    Create(memberType);
                    using (var newobj = DeclareLocal(memberType))
                    {
                        il.Stloc(newobj);
                        il.Ldloc(newobj);
                        EmitMemberAssign(type, node.Member);
                        il.Ldloc(newobj);
                    }
                    MarkLabelAndSurroundWithSP(memberIsNotNullLabel);
                }
                else
                {
                    owner = DeclareLocal(ownerType);
                    il.Stloc(owner);
                    il.Ldloc(owner);
                    EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
                    var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull");
                    il.Dup();
                    il.Brtrue(memberIsNotNullLabel);
                    il.Pop();
                    il.Ldloc(owner);
                    Create(memberType);
                    using (var newobj = DeclareLocal(memberType))
                    {
                        il.Stloc(newobj);
                        il.Ldloc(newobj);
                        EmitMemberAssign(type, node.Member);
                        il.Ldloc(newobj);
                    }
                    MarkLabelAndSurroundWithSP(memberIsNotNullLabel);
                }
            }
            return(result);
        }
        protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            Type    operandType;
            var     result = ExpressionEmittersCollection.Emit(node.Operand, context, returnDefaultValueLabel, ResultType.Value, extend, out operandType);
            GroboIL il     = context.Il;

            if (node.NodeType == ExpressionType.IsTrue || node.NodeType == ExpressionType.IsFalse)
            {
                if (!operandType.IsNullable())
                {
                    if (node.Method != null)
                    {
                        il.Call(node.Method);
                    }
                    else if (operandType == typeof(bool))
                    {
                        if (node.NodeType == ExpressionType.IsFalse)
                        {
                            il.Ldc_I4(1);
                            il.Xor();
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a type '" + operandType + "'");
                    }
                }
                else
                {
                    using (var temp = context.DeclareLocal(operandType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                        context.EmitHasValueAccess(operandType);
                        var returnFalseLabel = il.DefineLabel("returnFalse");
                        il.Brfalse(returnFalseLabel);
                        il.Ldloca(temp);
                        context.EmitValueAccess(operandType);
                        if (node.Method != null)
                        {
                            il.Call(node.Method);
                        }
                        else if (operandType == typeof(bool?))
                        {
                            if (node.NodeType == ExpressionType.IsFalse)
                            {
                                il.Ldc_I4(1);
                                il.Xor();
                            }
                        }
                        else
                        {
                            throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a type '" + operandType + "'");
                        }
                        var doneLabel = il.DefineLabel("done");
                        il.Br(doneLabel);
                        context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                        il.Ldc_I4(0);
                        context.MarkLabelAndSurroundWithSP(doneLabel);
                    }
                }
            }
            else
            {
                if (!operandType.IsNullable())
                {
                    if (node.Method != null)
                    {
                        il.Call(node.Method);
                    }
                    else
                    {
                        if (operandType.IsStruct())
                        {
                            throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a struct '" + operandType + "'");
                        }
                        switch (node.NodeType)
                        {
                        case ExpressionType.UnaryPlus:
                            break;

                        case ExpressionType.Negate:
                            il.Neg();
                            break;

                        case ExpressionType.NegateChecked:
                            using (var temp = context.DeclareLocal(operandType))
                            {
                                il.Stloc(temp);
                                il.Ldc_I4(0);
                                context.EmitConvert(typeof(int), operandType);
                                il.Ldloc(temp);
                                il.Sub_Ovf(operandType.Unsigned());
                            }
                            break;

                        case ExpressionType.Increment:
                            il.Ldc_I4(1);
                            context.EmitConvert(typeof(int), operandType);
                            il.Add();
                            break;

                        case ExpressionType.Decrement:
                            il.Ldc_I4(1);
                            context.EmitConvert(typeof(int), operandType);
                            il.Sub();
                            break;

                        case ExpressionType.OnesComplement:
                            il.Not();
                            break;

                        default:
                            throw new InvalidOperationException("Node type '" + node.NodeType + "' invalid at this point");
                        }
                    }
                }
                else
                {
                    using (var temp = context.DeclareLocal(operandType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                        context.EmitHasValueAccess(operandType);
                        var returnNullLabel = il.DefineLabel("returnLabel");
                        il.Brfalse(returnNullLabel);
                        Type argumentType = operandType.GetGenericArguments()[0];
                        if (node.Method != null)
                        {
                            il.Ldloca(temp);
                            context.EmitValueAccess(operandType);
                            il.Call(node.Method);
                        }
                        else
                        {
                            switch (node.NodeType)
                            {
                            case ExpressionType.UnaryPlus:
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                break;

                            case ExpressionType.Negate:
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                il.Neg();
                                break;

                            case ExpressionType.NegateChecked:
                                il.Ldc_I4(0);
                                context.EmitConvert(typeof(int), argumentType);
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                il.Sub_Ovf(argumentType.Unsigned());
                                break;

                            case ExpressionType.Increment:
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                il.Ldc_I4(1);
                                context.EmitConvert(typeof(int), argumentType);
                                il.Add();
                                break;

                            case ExpressionType.Decrement:
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                il.Ldc_I4(1);
                                context.EmitConvert(typeof(int), argumentType);
                                il.Sub();
                                break;

                            case ExpressionType.OnesComplement:
                                il.Ldloca(temp);
                                context.EmitValueAccess(operandType);
                                il.Not();
                                break;

                            default:
                                throw new InvalidOperationException("Node type '" + node.NodeType + "' invalid at this point");
                            }
                        }
                        il.Newobj(operandType.GetConstructor(new[] { argumentType }));
                        var doneLabel = il.DefineLabel("done");
                        il.Br(doneLabel);
                        context.MarkLabelAndSurroundWithSP(returnNullLabel);
                        context.EmitLoadDefaultValue(operandType);
                        context.MarkLabelAndSurroundWithSP(doneLabel);
                    }
                }
            }
            resultType = node.Type;
            return(result);
        }
예제 #33
0
        private Type BuildReaderInvoker()
        {
            var argument     = Type.GetGenericArguments()[0];
            var typeBuilder  = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class);
            var reader       = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private);
            var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private);
            var constructor  = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(IntPtr), typeof(long) });

            using (var il = new GroboIL(constructor))
            {
                il.Ldarg(0);            // stack: [this]
                il.Ldarg(1);            // stack: [this, reader]
                il.Stfld(reader);       // this.reader = reader; stack: []
                il.Ldarg(0);            // stack: [this]
                il.Ldarg(2);            // stack: [this, serializerId]
                il.Stfld(serializerId); // this.serializerId = serializerId; stack: []
                il.Ret();
            }
            var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] { typeof(byte[]) });

            using (var il = new GroboIL(method))
            {
                var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true);
                il.Ldarg(1);                                                                                                    // stack: [data]
                il.Ldc_I4(0);                                                                                                   // stack: [data, 0]
                il.Ldelema(typeof(byte));                                                                                       // stack: [&data[0]]
                il.Stloc(pinnedData);                                                                                           // pinnedData = &data[0]; stack: []
                var index = il.DeclareLocal(typeof(int), "index");
                il.Ldc_I4(0);                                                                                                   // stack: [0]
                il.Stloc(index);                                                                                                // index = 0; stack: []
                var context = il.DeclareLocal(typeof(ReaderContext), "context");
                il.Ldarg(0);                                                                                                    // stack: [this]
                il.Ldfld(serializerId);                                                                                         // stack: [this.serializerId]
                il.Ldarg(1);                                                                                                    // stack: [this.serializerId, data]
                il.Ldlen();                                                                                                     // stack: [this.serializerId, data.Length]
                il.Ldc_I4(0);                                                                                                   // stack: [this.serializerId, data.Length, 0]
                il.Ldc_I4(0);                                                                                                   // stack: [this.serializerId, data.Length, 0, 0]
                il.Newobj(typeof(ReaderContext).GetConstructor(new[] { typeof(long), typeof(int), typeof(int), typeof(int) })); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)]
                il.Stloc(context);                                                                                              // context = new ReaderContext(..); stack: []

                var result = il.DeclareLocal(argument, "result");
                il.Ldloc(pinnedData);                                                // stack: [data]
                il.Conv <IntPtr>();                                                  // stack: [(IntPtr)data]
                il.Ldloca(index);                                                    // stack: [(IntPtr)data, ref index]
                il.Ldloca(result);                                                   // stack: [(IntPtr)data, ref index, ref result]
                il.Ldloc(context);                                                   // stack: [(IntPtr)data, ref index, ref result, context]
                il.Ldarg(0);                                                         // stack: [(IntPtr)data, ref index, ref result, context, this]
                il.Ldfld(reader);                                                    // stack: [(IntPtr)data, ref index, ref result, context, this.reader]
                var parameterTypes = new[] { typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext) };
                il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: []
                il.FreePinnedLocal(pinnedData);                                      // pinnedData = null; stack: []
                var retLabel = il.DefineLabel("ret");
                il.Ldarg(1);                                                         // stack: [data]
                il.Ldlen();                                                          // stack: [data.Length]
                il.Ldloc(index);                                                     // stack: [data.Length, index]
                il.Beq(retLabel);                                                    // if(data.Length == index) goto ret; stack: []
                il.Ldstr("Encountered extra data");
                il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                il.Throw();

                il.MarkLabel(retLabel);
                il.Ldloc(result);
                il.Ret();
            }
            return(typeBuilder.CreateType());
        }