Пример #1
0
        public void TestDifferentPathsGeneric()
        {
            var assembly          = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
            var module            = assembly.DefineDynamicModule(Guid.NewGuid().ToString());
            var type              = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public);
            var method            = type.DefineMethod("Qzz", MethodAttributes.Public | MethodAttributes.Static);
            var genericParameters = method.DefineGenericParameters("TZzz");
            var parameter         = genericParameters[0];

            method.SetParameters(typeof(bool), typeof(C1 <>).MakeGenericType(parameter), typeof(C2 <>).MakeGenericType(parameter));
            method.SetReturnType(typeof(void));
            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                var label1 = il.DefineLabel("L1");
                il.Brfalse(label1);
                il.Ldarg(1);
                var label2 = il.DefineLabel("L2");
                il.Br(label2);
                il.MarkLabel(label1);
                il.Ldarg(2);
                il.MarkLabel(label2);
                il.Dup();
                il.Call(HackHelpers.GetMethodDefinition <I1 <int> >(x => F1(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter));
                il.Call(HackHelpers.GetMethodDefinition <I2 <int> >(x => F2(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter));
                il.Ret();
                Console.Write(il.GetILCode());
            }
        }
Пример #2
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 }));
        }
Пример #3
0
        private static Func <MethodBase, DynamicMethod> EmitTryCastToDynamicMethod()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(DynamicMethod), new[] { typeof(MethodBase) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var RTDynamicMethod_t = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic);
                if (RTDynamicMethod_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod'");
                }
                il.Ldarg(0);                  // stack: [method]
                il.Isinst(RTDynamicMethod_t); // stack: [method as RTDynamicMethod]
                il.Dup();                     // stack: [method as RTDynamicMethod, method as RTDynamicMethod]
                var retLabel = il.DefineLabel("ret");
                il.Brfalse(retLabel);         // if(!(method is RTDynamicMethod)] goto ret; stack: [method as RTDynamicMethod]
                var m_owner_f = RTDynamicMethod_t.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_owner_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod.m_owner'");
                }
                il.Ldfld(m_owner_f); // stack: [((RTDynamicMethod)method).m_owner]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <MethodBase, DynamicMethod>)method.CreateDelegate(typeof(Func <MethodBase, DynamicMethod>)));
        }
Пример #4
0
 private static void EmitStatic(GroboIL il, MethodInfo getMethod, MethodInfo staticMethod, GroboIL.Label returnFalse)
 {
     // Equals(a.Property, b.Property)
     il.Ldarg(0);
     il.Call(getMethod);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Call(staticMethod);
     il.Brfalse(returnFalse);
 }
Пример #5
0
        public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext)
        {
            var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] { Type, typeof(bool), typeof(WriterContext) }, sizeCounterBuilderContext.Module, true);

            sizeCounterBuilderContext.SetSizeCounterMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new SizeCounterMethodBuilderContext(sizeCounterBuilderContext, il);

                var notEmptyLabel = il.DefineLabel("notEmpty");
                if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty
                {
                    context.ReturnForNull();            // return for null
                }
                il.MarkLabel(notEmptyLabel);            // Now we know that obj is not empty

                if (!Type.IsValueType && IsReference && sizeCounterBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences))
                {
                    // Pack reference
                    var index = il.DeclareLocal(typeof(int));
                    context.LoadContext();                                                                                // stack: [context]
                    il.Dup();                                                                                             // stack: [context, context]
                    il.Ldfld(WriterContext.IndexField);                                                                   // stack: [context, context.index]
                    il.Stloc(index);                                                                                      // index = context.index; stack: [context]
                    il.Ldfld(WriterContext.ObjectsField);                                                                 // stack: [context.objects]
                    context.LoadObj();                                                                                    // stack: [context.objects, obj]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.ContainsKey(null))); // stack: [context.object.ContainsKey(obj)]
                    var storeLocationLabel = il.DefineLabel("storeLocation");
                    il.Brfalse(storeLocationLabel);                                                                       // if(!context.objects.ContainsKey(obj)) goto storeLocation; stack: []
                    context.LoadContext();                                                                                // stack: [context]
                    il.Dup();                                                                                             // stack: [context, context]
                    il.Ldfld(WriterContext.ReferencesField);                                                              // stack: [context, context.references]
                    il.Ldc_I4(1);                                                                                         // stack: [context, context.references, 1]
                    il.Add();                                                                                             // stack: [context, context.references + 1]
                    il.Stfld(WriterContext.ReferencesField);                                                              // context.references += 1; stack: []
                    il.Ldc_I4(5);                                                                                         // stack: [5]
                    il.Ret();                                                                                             // return 5
                    il.MarkLabel(storeLocationLabel);
                    context.LoadContext();                                                                                // stack: [context]
                    il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance));     // stack: [context.objects]
                    context.LoadObj();                                                                                    // stack: [context.objects, obj]
                    il.Ldloc(index);                                                                                      // stack: [context.objects, obj, index]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.Add(null, 0)));      // context.objects.Add(obj, index);
                }

                CountSizeNotEmpty(context); // Count size
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate);
        }
Пример #6
0
        public void TestLabelHasNotBeenMarked()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), Type.EmptyTypes, typeof(string), true);
            var il     = new GroboIL(method);
            var label  = il.DefineLabel("L");

            il.Ldc_I4(0);
            il.Brfalse(label);
            il.Ret();
            var e = Assert.Throws <InvalidOperationException>(il.Dispose);

            Assert.AreEqual("The label 'L_0' has not been marked", e.Message);
        }
Пример #7
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);
        }
Пример #8
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);
        }
Пример #9
0
        public void TestLabelHasBeenMarkedTwice()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), Type.EmptyTypes, typeof(string), true);
            var il     = new GroboIL(method);
            var label  = il.DefineLabel("L");

            il.Ldc_I4(0);
            il.Brfalse(label);
            il.Ldc_I4(1);
            il.Pop();
            il.MarkLabel(label);
            il.Ldc_I4(2);
            il.Pop();
            var e = Assert.Throws <InvalidOperationException>(() => il.MarkLabel(label));

            Assert.AreEqual("The label 'L_0' has already been marked", e.Message);
        }
Пример #10
0
        public void TestBrfalse()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(C2) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                il.Dup();
                var label = il.DefineLabel("L");
                il.Brfalse(label);
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2()));
                il.MarkLabel(label);
                il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null)));
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
        }
        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);
        }
Пример #12
0
        public void TestDifferentStructs()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(int) }, typeof(Test));
            var il     = new GroboIL(method);
            var loc1   = il.DeclareLocal(typeof(int?));
            var loc2   = il.DeclareLocal(typeof(Qxx?));
            var label1 = il.DefineLabel("zzz");

            il.Ldarg(0);
            il.Brfalse(label1);
            il.Ldloc(loc1);
            var label2 = il.DefineLabel("qxx");

            il.Br(label2);
            il.MarkLabel(label1);
            il.Ldloc(loc2);
            Assert.Throws <InvalidOperationException>(() => il.MarkLabel(label2));
        }
        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);
        }
Пример #14
0
        private Func <string, string> BuildSwitch4()
        {
            Init(new[] { "0", "2", "5", "1000001", "7", "1000000" });
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(string) }, Module, true);

            using (var il = new GroboIL(dynamicMethod))
            {
                var zzzLabel = il.DefineLabel("zzz");
                var qxxLabel = il.DefineLabel("qxx");
                var qzzLabel = il.DefineLabel("qzz");
                var xxxLabel = il.DefineLabel("xxx");
                var index    = il.DeclareLocal(typeof(uint));
                il.Ldfld(typeof(TestPerformance).GetField("testValues2"));
                il.Ldarg(0);
                il.Call(typeof(object).GetMethod("GetHashCode"), typeof(string));
                il.Ldc_I4(testValues2.Length);
                il.Rem(true);
                il.Stloc(index);
                il.Ldloc(index);
                il.Ldelem(typeof(string));
                il.Ldarg(0);
                il.Call(typeof(object).GetMethod("Equals", new[] { typeof(object) }), typeof(string));
                il.Brfalse(xxxLabel);
                il.Ldfld(typeof(TestPerformance).GetField("indexes2"));
                il.Ldloc(index);
                il.Ldelem(typeof(int));
                il.Switch(zzzLabel, zzzLabel, qxxLabel, qxxLabel, qzzLabel, qzzLabel);
                il.Br(xxxLabel);
                il.MarkLabel(zzzLabel);
                il.Ldstr("zzz");
                il.Ret();
                il.MarkLabel(qxxLabel);
                il.Ldstr("qxx");
                il.Ret();
                il.MarkLabel(qzzLabel);
                il.Ldstr("qzz");
                il.Ret();
                il.MarkLabel(xxxLabel);
                il.Ldstr("xxx");
                il.Ret();
            }
            return((Func <string, string>)dynamicMethod.CreateDelegate(typeof(Func <string, string>)));
        }
Пример #15
0
        public void TestZ2()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(A), new[] { typeof(bool), typeof(B), typeof(C) }, typeof(Test));

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                var label1 = il.DefineLabel("label");
                il.Brfalse(label1);
                il.Ldarg(1);
                var label2 = il.DefineLabel("label");
                il.Br(label2);
                il.MarkLabel(label1);
                il.Ldarg(2);
                il.MarkLabel(label2);
                il.Ret();
                Console.Write(il.GetILCode());
            }
        }
        private static Func <object, object> EmitResolveVarArgsMethod()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var VarArgMethod_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.VarArgMethod");
                if (VarArgMethod_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.VarArgMethod'");
                }
                il.Ldarg(0);               // stack: [value]
                il.Isinst(VarArgMethod_t); // stack: [(VarArgMethod)value]
                var retLabel = il.DefineLabel("ret");
                il.Dup();                  // stack: [(VarArgMethod)value, (VarArgMethod)value]
                il.Brfalse(retLabel);      // if(!(value is VarArgMethod)) goto ret; stack: [value as VarArgMethod]
                var m_method_f = VarArgMethod_t.GetField("m_method", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_method_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_method'");
                }
                var m_dynamicMethod_f = VarArgMethod_t.GetField("m_dynamicMethod", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_dynamicMethod_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_dynamicMethod'");
                }
                var temp = il.DeclareLocal(VarArgMethod_t);
                il.Dup();
                il.Stloc(temp);              // temp = (VarArgMethod)value; stack: [(VarArgMethod)value]
                il.Ldfld(m_method_f);        // stack: [((VarArgMethod)value).m_method]
                il.Dup();                    // stack: [((VarArgMethod)value).m_method, ((VarArgMethod)value).m_method]
                il.Brtrue(retLabel);         // if(((VarArgMethod)value).m_method != null) goto ret; stack: [((VarArgMethod)value).m_method]
                il.Pop();                    // stack: []
                il.Ldloc(temp);              // stack: [(VarArgMethod)value]
                il.Ldfld(m_dynamicMethod_f); // stack: [((VarArgMethod)value).m_dynamicMethod]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>)));
        }
Пример #17
0
        private IQxx BuildIfs(ModuleBuilder module, string[] keys)
        {
            var numberOfCases = keys.Length;
            var typeBuilder   = module.DefineType("Ifs" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public);

            typeBuilder.AddInterfaceImplementation(typeof(IQxx));
            var fields = new FieldInfo[numberOfCases];

            for (var i = 0; i < numberOfCases; ++i)
            {
                fields[i] = typeBuilder.DefineField(keys[i], typeof(int), FieldAttributes.Public);
            }
            var method = typeBuilder.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { typeof(string), typeof(int) });

            method.DefineParameter(1, ParameterAttributes.In, "key");
            method.DefineParameter(2, ParameterAttributes.In, "value");
            using (var il = new GroboIL(method))
            {
                var doneLabel = il.DefineLabel("done");
                for (var i = 0; i < numberOfCases; ++i)
                {
                    il.Ldarg(1);                     // stack: [key]
                    il.Ldstr(keys[i]);               // stack: [key, keys[i]]
                    il.Call(stringEqualityOperator); // stack: [key == keys[i]]
                    var nextKeyLabel = il.DefineLabel("nextKey");
                    il.Brfalse(nextKeyLabel);        // if(key != keys[i]) goto nextKey; stack: []
                    il.Ldarg(0);
                    il.Ldarg(2);
                    il.Stfld(fields[i]);
                    il.Br(doneLabel);
                    il.MarkLabel(nextKeyLabel);
                }
                il.MarkLabel(doneLabel);
                il.Ret();
            }
            typeBuilder.DefineMethodOverride(method, typeof(IQxx).GetMethod("Set"));
            var type = typeBuilder.CreateType();

            return((IQxx)Activator.CreateInstance(type));
        }
        private static Func <object, object> EmitResolveGenericMethodInfo()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var GenericMethodInfo_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.GenericMethodInfo");
                if (GenericMethodInfo_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.GenericMethodInfo'");
                }
                il.Ldarg(0);                    // stack: [value]
                il.Isinst(GenericMethodInfo_t); // stack: [(GenericMethodInfo)value]
                var retLabel = il.DefineLabel("ret");
                il.Dup();                       // stack: [(GenericMethodInfo)value, (GenericMethodInfo)value]
                il.Brfalse(retLabel);           // if(!(value is GenericMethodInfo)) goto ret; stack: [value as GenericMethodInfo]
                var m_methodHandle_f = GenericMethodInfo_t.GetField("m_methodHandle", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_methodHandle_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_methodHandle'");
                }
                var m_context_f = GenericMethodInfo_t.GetField("m_context", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_context_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_context'");
                }
                var temp = il.DeclareLocal(GenericMethodInfo_t);
                il.Dup();
                il.Stloc(temp);                 // temp = (GenericMethodInfo)value; stack: [(GenericMethodInfo)value]
                il.Ldfld(m_methodHandle_f);     // stack: [((GenericMethodInfo)value).m_methodHandle]
                il.Ldloc(temp);                 // stack: [((GenericMethodInfo)value).m_methodHandle, (GenericMethodInfo)value]
                il.Ldfld(m_context_f);          // stack: [((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context]
                var getMethodFromHandle_m = HackHelpers.GetMethodDefinition <int>(x => MethodBase.GetMethodFromHandle(default(RuntimeMethodHandle), default(RuntimeTypeHandle)));
                il.Call(getMethodFromHandle_m); // stack: [MethodBase.GetMethodFromHandle(((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context)]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>)));
        }
Пример #19
0
        public static TryGetValueDelegate <T> Build <T>(string[] keys, T[] values)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(T[]), typeof(string), typeof(T).MakeByRefType() }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                for (int i = 0; i < keys.Length; ++i)
                {
                    il.Ldarg(1);                     // stack: [key]
                    il.Ldstr(keys[i]);               // stack: [key, keys[i]]
                    var nextKeyLabel = il.DefineLabel("nextKey");
                    il.Call(stringEqualityOperator); // stack: [key == keys[i]]
                    il.Brfalse(nextKeyLabel);        // if(key != keys[i]) goto nextKey; stack: []
                    il.Ldarg(2);                     // stack: [ref value]
                    il.Ldarg(0);                     // stack: [ref value, values]
                    il.Ldc_I4(i);                    // stack: [ref value, values, i]
                    il.Ldelem(typeof(T));            // stack: [ref value, values[i]]
                    il.Stind(typeof(T));             // value = values[i]; stack: []
                    il.Ldc_I4(1);                    // stack: [true]
                    il.Ret();
                    il.MarkLabel(nextKeyLabel);
                }
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), values));
        }
Пример #20
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)));
        }
Пример #21
0
        public void TestDifferentPaths()
        {
            Console.WriteLine(Formatter.Format(typeof(Dictionary <string, int>).GetProperty("Values", BindingFlags.Public | BindingFlags.Instance).GetGetMethod()));
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(bool), typeof(C1), typeof(C2) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                var label1 = il.DefineLabel("L1");
                il.Brfalse(label1);
                il.Ldarg(1);
                var label2 = il.DefineLabel("L2");
                il.Br(label2);
                il.MarkLabel(label1);
                il.Ldarg(2);
                il.MarkLabel(label2);
                il.Dup();
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => F1(x)));
                il.Call(HackHelpers.GetMethodDefinition <I2>(x => F2(x)));
                il.Ret();
                Console.Write(il.GetILCode());
            }
            var action = method.CreateDelegate(typeof(Action <bool, C1, C2>));
        }
        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);
        }
Пример #23
0
        public void TestZzz2()
        {
            var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave);

            var mod  = asm.DefineDynamicModule("mymod", "tmp.dll", true);
            var type = mod.DefineType("baz", TypeAttributes.Public | TypeAttributes.Class);
            var meth = type.DefineMethod("go", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int) });

            var document = mod.DefineDocument("TestDebug2.txt", Guid.Empty, Guid.Empty, Guid.Empty); //Expression.SymbolDocument("TestDebug2.txt");

            //var di = Expression.DebugInfo(sdi, 2, 2, 2, 13);

            //var exp = Expression.Divide(Expression.Constant(2), Expression.Subtract(Expression.Constant(4), Expression.Constant(4)));
            //var block = Expression.Block(di, exp);

            using (var il = new GroboIL(meth))
            {
//                        nop                      // []
//        nop                      // []
//        ldc.i4.1                 // [Int32]
//        brfalse ifFalse_7        // []
//        nop                      // []
//        ldarg.0                  // [Int32]
//        br done_10               // [Int32]
//ifFalse_7:                       // []
//        nop                      // []
//        ldarg.0                  // [Int32]
//done_10:                         // [Int32]
//        stloc local_0            // []
//        nop                      // []
//        ldloc local_0            // [Int32]
//        ret                      // []

//                var tst = Expression.Block(Expression.DebugInfo(sdi, 6, 20, 6, 27), Expression.Constant(true));
//                var iftrue = Expression.Block(Expression.DebugInfo(sdi, 10, 20, 10, 26), variable);
//                var iffalse = Expression.Block(Expression.DebugInfo(sdi, 14, 20, 14, 26), variable);
//                var exp = Expression.Condition(tst, iftrue, iffalse);
//
//                /*
//                var returnTarget = Expression.Label(typeof(int));
//                var returnExpression = Expression.Return(returnTarget, exp, typeof(int));
//                var returnLabel = Expression.Label(returnTarget, Expression.Constant(0));
//                */
//
//                var block = Expression.Block(typeof(int), new[] { temp },
//                    Expression.DebugInfo(sdi, 4, 15, 4, 16), Expression.Assign(temp, exp), Expression.DebugInfo(sdi, 17, 16, 17, 21), temp);
//                //var block = Expression.Block(Expression.DebugInfo(sdi, 4, 16, 17, 10), Expression.Assign(temp, exp)));
//                var kek = Expression.Lambda(block, variable);

                il.MarkSequencePoint(document, 4, 15, 4, 16);
                il.Nop();
                il.Nop();
                il.Ldc_I4(1);
                il.MarkSequencePoint(document, 6, 20, 6, 27);
                var brFalse = il.DefineLabel("brFalse");
                il.Brfalse(brFalse);
                il.MarkSequencePoint(document, 10, 20, 10, 26);
                il.Nop();
                il.Ldarg(0);
                il.Ldc_I4(100);
                il.Add();
                var doneLabel = il.DefineLabel("done");
                il.Br(doneLabel);
                il.MarkSequencePoint(document, 14, 20, 14, 26);
                il.MarkLabel(brFalse);
                il.Nop();
                il.Ldarg(0);
                il.Ldc_I4(10);
                il.Add();
                il.MarkLabel(doneLabel);
                il.MarkSequencePoint(document, 16, 16, 16, 21);
                var local = il.DeclareLocal(typeof(int));
                il.Stloc(local);
                il.Nop();
                il.MarkSequencePoint(document, 17, 16, 17, 21);
                il.Ldloc(local);
                il.Ret();
            }

            var newtype = type.CreateType();

            asm.Save("tmp.dll");
            newtype.GetMethod("go").Invoke(null, new object[] { 0 });
            //meth.Invoke(null, new object[0]);
            //lambda.DynamicInvoke(new object[0]);
            Console.WriteLine(" ");
        }
Пример #24
0
        public void TestZzz()
        {
            var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave);

            var mod  = asm.DefineDynamicModule("mymod", "tmp.dll", true);
            var type = mod.DefineType("baz", TypeAttributes.Public | TypeAttributes.Class);
            var meth = type.DefineMethod("go", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int) });

            var document = mod.DefineDocument("TestDebug2.txt", Guid.Empty, Guid.Empty, Guid.Empty); //Expression.SymbolDocument("TestDebug2.txt");

            meth.DefineParameter(1, ParameterAttributes.In, "$x");

            //var di = Expression.DebugInfo(sdi, 2, 2, 2, 13);

            //var exp = Expression.Divide(Expression.Constant(2), Expression.Subtract(Expression.Constant(4), Expression.Constant(4)));
            //var block = Expression.Block(di, exp);

            using (var il = new GroboIL(meth))
            {
//                var tst = Expression.Block(Expression.DebugInfo(sdi, 6, 20, 6, 27), Expression.Equal(variable, zero));
//                var iftrue = Expression.Block(Expression.DebugInfo(sdi, 10, 20, 10, 26), Expression.Add(variable, two));
//                var iffalse = Expression.Block(Expression.DebugInfo(sdi, 14, 20, 14, 26), Expression.Divide(variable, two));
//                var exp = Expression.Condition(tst, iftrue, iffalse);
//                var block = Expression.Block(Expression.DebugInfo(sdi, 4, 16, 15, 10), exp);

//                        nop                      // []
//        nop                      // []
//        ldarg.0                  // [Int32]
//        ldc.i4.0                 // [Int32, Int32]
//        ceq                      // [Int32]
//        brfalse ifFalse_5        // []
//        nop                      // []
//        ldarg.0                  // [Int32]
//        ldc.i4.2                 // [Int32, Int32]
//        add                      // [Int32]
//        br done_8                // [Int32]
//ifFalse_5:                       // []
//        nop                      // []
//        ldarg.0                  // [Int32]
//        ldc.i4.2                 // [Int32, Int32]
//        div                      // [Int32]
//done_8:                          // [Int32]
//        ret                      // []

                il.MarkSequencePoint(document, 3, 9, 3, 15);
                il.Nop();
                il.MarkSequencePoint(document, 4, 13, 4, 19);
                il.Nop();
                il.Ldarg(0);
                il.Ldc_I4(0);
                il.Ceq();
                var label = il.DefineLabel("ifFalse");
                il.Brfalse(label);
                il.MarkSequencePoint(document, 7, 13, 7, 19);
                il.Nop();
                il.Ldarg(0);
                il.Ldc_I4(2);
                il.Add();
                var doneLabel = il.DefineLabel("done");
                il.Br(doneLabel);
                il.MarkLabel(label);
                il.MarkSequencePoint(document, 10, 13, 10, 19);
                il.Nop();
                il.Ldarg(0);
                il.Ldc_I4(2);
                il.Mul();
                il.MarkLabel(doneLabel);
                il.MarkSequencePoint(document, 12, 5, 12, 6);
                il.Nop();
                il.Ret();
            }

            var newtype = type.CreateType();

            asm.Save("tmp.dll");
            newtype.GetMethod("go").Invoke(null, new object[] { 0 });
            //meth.Invoke(null, new object[0]);
            //lambda.DynamicInvoke(new object[0]);
            Console.WriteLine(" ");
        }
Пример #25
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);
 }
Пример #26
0
 private static void EmitStatic(GroboIL il, MethodInfo getMethod, MethodInfo staticMethod, GroboIL.Label returnFalse)
 {
     // Equals(a.Property, b.Property)
     il.Ldarg(0);
     il.Call(getMethod);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Call(staticMethod);
     il.Brfalse(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);
        }
Пример #28
0
        private static Type BuildTypeInternal(Type type)
        {
            var parentType  = typeof(ValidationResultTreeNode);
            var properties  = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var typeBuilder = module.DefineType(type.Name + "_" + id++, TypeAttributes.Class | TypeAttributes.Public, parentType);

            typesBeingBuilt[type] = typeBuilder;

            var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { parentType });

            using (var il = new GroboIL(constructor))
            {
                il.Ldarg(0);              // stack: [this]
                il.Ldarg(1);              // stack: [this, parent]
                var baseConstructor = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { parentType }, null);
                il.Call(baseConstructor); // base(parent); stack: []
                il.Ret();
            }

            var fields = new Dictionary <string, FieldBuilder>();

            foreach (var property in properties)
            {
                var  propertyType = property.PropertyType;
                Type fieldType;
                if (propertyType.IsArray)
                {
                    fieldType = typeof(ValidationResultTreeArrayNode <>).MakeGenericType(BuildType(propertyType.GetElementType()));
                }
                else if (propertyType.IsDictionary() || propertyType == typeof(Hashtable))
                {
                    fieldType = typeof(ValidationResultTreeUniversalNode);
                }
                else
                {
                    fieldType = BuildType(propertyType, true);
                }
                var field = typeBuilder.DefineField(property.Name, fieldType, FieldAttributes.Public);
                fields.Add(property.Name, field);
            }

            var getChildrenMethod        = parentType.GetMethod("GetChildren", BindingFlags.Instance | BindingFlags.NonPublic);
            var getChildrenMethodBuilder = typeBuilder.DefineMethod(getChildrenMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(IEnumerable <KeyValuePair <object, ValidationResultTreeNode> >), Type.EmptyTypes);

            using (var il = new GroboIL(getChildrenMethodBuilder))
            {
                var listType        = typeof(List <KeyValuePair <object, ValidationResultTreeNode> >);
                var addMethod       = listType.GetMethod("Add", new[] { typeof(KeyValuePair <object, ValidationResultTreeNode>) });
                var itemConstructor = typeof(KeyValuePair <object, ValidationResultTreeNode>).GetConstructor(new[] { typeof(object), parentType });
                var list            = il.DeclareLocal(listType);
                il.Newobj(listType.GetConstructor(Type.EmptyTypes)); // stack: [new List<>()]
                il.Stloc(list);                                      // list = new List<>(); stack: []
                foreach (var field in fields.Values)
                {
                    il.Ldarg(0);                // stack: [this]
                    il.Ldfld(field);            // stack: [this.field]
                    var nextLabel = il.DefineLabel("next");
                    il.Brfalse(nextLabel);      // if(this.field == null) goto next; stack: []
                    il.Ldloc(list);             // stack: [list]
                    il.Ldstr(field.Name);       // stack: [list, field.Name]
                    il.Ldarg(0);                // stack: [list, field.Name, this]
                    il.Ldfld(field);            // stack: [list, field.Name, this.field]
                    il.Newobj(itemConstructor); // stack: [list, new KeyValuePair<object, ValidationResultTreeNode>(field.Name, this.field)]
                    il.Call(addMethod);         // list.Add(new KeyValuePair<object, ValidationResultTreeNode>(field.Name, this.field)); stack: []
                    il.MarkLabel(nextLabel);
                }

                il.Ldloc(list);
                il.Ret();
            }

            typeBuilder.DefineMethodOverride(getChildrenMethodBuilder, getChildrenMethod);

            var traverseEdgeMethod        = parentType.GetMethod("TraverseEdge", BindingFlags.Instance | BindingFlags.NonPublic);
            var traverseEdgeMethodBuilder = typeBuilder.DefineMethod(traverseEdgeMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, parentType, new[] { typeof(Expression) });

            using (var il = new GroboIL(traverseEdgeMethodBuilder))
            {
                il.Ldarg(1);                                                                   // stack: [edge]
                il.Castclass(typeof(MemberExpression));                                        // stack: [(MemberExpression)edge]
                il.Call(HackHelpers.GetProp <MemberExpression>(x => x.Member).GetGetMethod()); // stack: [((MemberExpresion)edge).Member]
                il.Call(HackHelpers.GetProp <MemberInfo>(x => x.Name).GetGetMethod());         // stack: [((MemberExpresion)edge).Member.Name]
                var member = il.DeclareLocal(typeof(string));
                il.Stloc(member);
                foreach (var property in properties)
                {
                    il.Ldstr(property.Name); // stack: [property.Name]
                    il.Ldloc(member);        // stack: [property.Name, member]
                    il.Call(typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public));
                    var nextLabel = il.DefineLabel("next");
                    il.Brfalse(nextLabel);           // if(property.Name != member) goto next; stack: []
                    il.Ldarg(0);                     // stack: [this]
                    il.Ldfld(fields[property.Name]); // stack: [this.field]
                    il.Ret();                        // return this.field;
                    il.MarkLabel(nextLabel);
                }

                il.Ldnull();
                il.Ret();
            }

            typeBuilder.DefineMethodOverride(traverseEdgeMethodBuilder, traverseEdgeMethod);

            var result = typeBuilder.CreateTypeInfo();

            typesBeingBuilt[type] = null;
            return(result);
        }
Пример #29
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)));
        }
Пример #30
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);
        }
Пример #31
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);
 }
        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);
        }
        private static Type BuildMutatorsTreeCreator(int numberOfGenericParameters)
        {
            var typeBuilder       = module.DefineType("MutatorsTreeCreator_" + numberOfGenericParameters, TypeAttributes.Public | TypeAttributes.Class);
            var genericParameters = typeBuilder.DefineGenericParameters(new[] { "TSource" }.Concat(new int[numberOfGenericParameters - 1].Select((i, index) => "T" + (index + 1))).ToArray());

            var interfaceType = typeof(IMutatorsTreeCreator <>).MakeGenericType(genericParameters.Last());
            var method        = TypeBuilder.GetMethod(interfaceType, typeof(IMutatorsTreeCreator <>).GetMethod(getMutatorsTreeMethodName, BindingFlags.Public | BindingFlags.Instance));
            var methodBuilder = typeBuilder.DefineMethod(getMutatorsTreeMethodName, MethodAttributes.Public | MethodAttributes.Virtual, typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters.Last()),
                                                         new[] { typeof(IDataConfiguratorCollectionFactory), typeof(IConverterCollectionFactory), typeof(MutatorsContext[]), typeof(MutatorsContext[]) });

            using (var il = new GroboIL(methodBuilder))
            {
                il.Ldarg(1);                                                                                                                      // stack: [dataConfiguratorCollectionFactory]
                il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[0]), typeof(IDataConfiguratorCollectionFactory)); // stack: [dataConfiguratorCollectionFactory.Get<TSource> = collection]

                var sourceCollectionIsNullLabel = il.DefineLabel("sourceCollectionIsNull");
                il.Dup();                                // stack: [collection, collection]
                il.Brfalse(sourceCollectionIsNullLabel); // if(collection == null) goto sourceCollectionIsNull; stack: [collection]

                il.Ldarg(3);                             // stack: [collection, mutatorsContexts]
                il.Ldc_I4(0);                            // stack: [collection, mutatorsContexts, 0]
                il.Ldelem(typeof(MutatorsContext));      // stack: [collection, mutatorsContexts[0]]
                il.Ldc_I4(0);                            // stack: [collection, mutatorsContexts[0], 0]
                // todo ich: избавиться от константы
                var collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[0]);
                il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [collection.GetMutatorsTree(mutatorsContexts[0], 0)]

                il.MarkLabel(sourceCollectionIsNullLabel);

                var current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[0]));
                for (var i = 0; i < numberOfGenericParameters - 1; ++i)
                {
                    // First: Migrate tree
                    il.Stloc(current);
                    il.Ldarg(2);                                                                                                                                  // stack: [converterCollectionFactory]
                    il.Call(getConverterCollectionMethod.MakeGenericMethod(genericParameters[i + 1], genericParameters[i]), typeof(IConverterCollectionFactory)); // stack: [converterCollectionFactory.Get<T_i, T_i+1> = converterCollection]
                    il.Dup();                                                                                                                                     // stack: [converterCollection, converterCollection]
                    il.Ldloc(current);                                                                                                                            // stack: [converterCollection, converterCollection, current]
                    il.Ldarg(4);                                                                                                                                  // stack: [converterCollection, converterCollection, current, converterContexts]
                    il.Ldc_I4(i);                                                                                                                                 // stack: [converterCollection, converterCollection, current, converterContexts, i]
                    il.Ldelem(typeof(MutatorsContext));                                                                                                           // stack: [converterCollection, converterCollection, current, converterContexts[i]]
                    // todo ich: избавиться от константы
                    //il.Call(collectionType.GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])]
                    collectionType = typeof(IConverterCollection <,>).MakeGenericType(genericParameters[i + 1], genericParameters[i]);
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])]
                    current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[i + 1]));
                    il.Stloc(current);                                                                                                                                                  // current = converterCollection.Migrate(current, converterContexts[i]); stack: [converterCollection]

                    // Second: Merge with validations tree
                    il.Ldarg(4);                              // stack: [converterCollection, converterContexts]
                    il.Ldc_I4(i);                             // stack: [converterCollection, converterContexts, i]
                    il.Ldelem(typeof(MutatorsContext));       // stack: [converterCollection, converterContexts[i]]
                    il.Ldc_I4(numberOfGenericParameters + i); // stack: [converterCollection, converterContexts[i], n + i]
                    // todo ich: избавиться от константы
                    //il.Call(collectionType.GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree]
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree]
                    il.Ldloc(current);                                                                                                                                                             // stack: [validationsTree, current]
                    //var mutatorsTreeType = typeof(MutatorsTreeBase<>).MakeGenericType(genericParameters[i + 1]);
                    //il.Call(mutatorsTreeType.GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance), mutatorsTreeType); // stack: [validationsTree.Merge(current)]
                    //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current)]
                    il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current)]

                    // Third: Merge with current mutators tree
                    il.Ldarg(1);                                                                                                                          // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory]
                    il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[i + 1]), typeof(IDataConfiguratorCollectionFactory)); // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory.Get<T_i+1> = collection]

                    var collectionIsNullLabel = il.DefineLabel("collectionIsNull");
                    il.Dup();                           // stack: [validationsTree.Merge(current), collection, collection]
                    il.Brfalse(collectionIsNullLabel);  // if(collection == null) goto collectionIsNull; stack: [validationsTree.Merge(current), collection]

                    il.Ldarg(3);                        // stack: [validationsTree.Merge(current), collection, mutatorsContexts]
                    il.Ldc_I4(i + 1);                   // stack: [validationsTree.Merge(current), collection, mutatorsContexts, i + 1]
                    il.Ldelem(typeof(MutatorsContext)); // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1]]
                    il.Ldc_I4(i + 1);                   // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1], 0]
                    // todo ich: избавиться от константы
                    collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[i + 1]);
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [validationsTree.Merge(current), collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)]

                    il.MarkLabel(collectionIsNullLabel);

                    //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current]
                    il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current]
                }

                il.Ret();
            }

            typeBuilder.DefineMethodOverride(methodBuilder, method);
            typeBuilder.AddInterfaceImplementation(interfaceType);
            return(typeBuilder.CreateType());
        }