예제 #1
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        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());
            }
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            if (node.Conversion != null)
            {
                throw new NotSupportedException("Coalesce with conversion is not supported");
            }
            // note ich: баг решарпера
            // ReSharper disable HeuristicUnreachableCode
            var     left  = node.Left;
            var     right = node.Right;
            GroboIL il    = context.Il;

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

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

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

            context.MarkLabelAndSurroundWithSP(valueIsNotNullLabel);
            resultType = node.Type;
            return(result);
            // ReSharper restore HeuristicUnreachableCode
        }
예제 #3
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestFarsh()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int) }, typeof(Test));

            using (var il = new GroboIL(method))
            {
                var temp = il.DeclareLocal(typeof(int));
                il.Ldarg(0);   // stack: [x]
                var label0 = il.DefineLabel("L");
                il.Br(label0); // goto L_0; stack: [x]

                il.Ldstr("zzz");
                il.Ldobj(typeof(DateTime));
                il.Mul();
                il.Initobj(typeof(int));

                var label1 = il.DefineLabel("L");
                il.MarkLabel(label1);  // stack: [x, 2]
                il.Stloc(temp);        // temp = 2; stack: [x]
                var label2 = il.DefineLabel("L");
                il.MarkLabel(label2);  // stack: [cur]
                il.Ldarg(0);           // stack: [cur, x]
                il.Mul();              // stack: [cur * x = cur]
                il.Ldloc(temp);        // stack: [cur, temp]
                il.Ldc_I4(1);          // stack: [cur, temp, 1]
                il.Sub();              // stack: [cur, temp - 1]
                il.Stloc(temp);        // temp = temp - 1; stack: [cur]
                il.Ldloc(temp);        // stack: [cur, temp]
                il.Ldc_I4(0);          // stack: [cur, temp, 0]
                il.Bgt(label2, false); // if(temp > 0) goto L_2; stack: [cur]
                var label3 = il.DefineLabel("L");
                il.Br(label3);         // goto L_3; stack: [cur]
                il.MarkLabel(label0);  // stack: [x]
                il.Ldc_I4(2);          // stack: [x, 2]
                il.Br(label1);         // goto L_1; stack: [x, 2]
                il.MarkLabel(label3);  // stack: [cur]
                il.Ret();              // return cur; stack: []
                Console.Write(il.GetILCode());
            }
        }
예제 #4
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        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);
        }
예제 #6
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        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());
            }
        }
예제 #7
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>)));
        }
예제 #8
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestBrtrue()
        {
            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.Brtrue(label);
                var label2 = il.DefineLabel("L");
                il.Br(label2);
                il.MarkLabel(label);
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2()));
                il.MarkLabel(label2);
                il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null)));
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
        }
예제 #9
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        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));
        }
예제 #10
0
        private Func <int, string> BuildSwitch2()
        {
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(int) }, 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("testValues"));
                il.Ldarg(0);
                il.Ldc_I4(14);
                il.Rem(true);
                il.Stloc(index);
                il.Ldloc(index);
                il.Ldelem(typeof(int));
                il.Ldarg(0);
                il.Bne_Un(xxxLabel);
                il.Ldfld(typeof(TestPerformance).GetField("indexes"));
                il.Ldloc(index);
                il.Ldelem(typeof(int));
                il.Switch(zzzLabel, zzzLabel, qxxLabel, qzzLabel, qzzLabel, qxxLabel);
                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 <int, string>)dynamicMethod.CreateDelegate(typeof(Func <int, string>)));
        }
        private static void EmitLoadIndex(Expression index, EmittingContext context, Type arrayType)
        {
            GroboIL il = context.Il;

            GroboIL.Label indexIsNullLabel = context.CanReturn ? il.DefineLabel("indexIsNull") : null;
            Type          indexType;
            bool          labelUsed = ExpressionEmittersCollection.Emit(index, context, indexIsNullLabel, out indexType); // stack: [array, index]

            if (indexType != typeof(int))
            {
                throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'");
            }
            if (labelUsed && context.CanReturn)
            {
                var indexIsNotNullLabel = il.DefineLabel("indexIsNotNull");
                il.Br(indexIsNotNullLabel);
                context.MarkLabelAndSurroundWithSP(indexIsNullLabel);
                il.Pop();
                il.Ldc_I4(0);
                context.MarkLabelAndSurroundWithSP(indexIsNotNullLabel);
            }
        }
예제 #12
0
        private Func <int, string> BuildSwitch1()
        {
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(int) }, Module, true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldarg(0);
                var zzzLabel = il.DefineLabel("zzz");
                var qxxLabel = il.DefineLabel("qxx");
                var qzzLabel = il.DefineLabel("qzz");
                var xxxLabel = il.DefineLabel("xxx");
                il.Switch(zzzLabel, xxxLabel, zzzLabel);
                il.Ldarg(0);
                il.Ldc_I4(5);
                il.Sub();
                il.Switch(qxxLabel, xxxLabel, qzzLabel);
                il.Ldarg(0);
                il.Ldc_I4(0xf4240);
                il.Sub();
                il.Switch(qzzLabel, qxxLabel);
                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 <int, string>)dynamicMethod.CreateDelegate(typeof(Func <int, string>)));
        }
예제 #13
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        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>));
        }
예제 #14
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(" ");
        }
        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);
        }
예제 #16
0
        public void TestLocalloc()
        {
            // private static unsafe int GetSum(byte length)
            // {
            //     byte* bytes = stackalloc byte[length];
            //     for (byte i = 0; i < length; ++i)
            //     {
            //         bytes[i] = i;
            //     }
            //     int sum = 0;
            //     for (byte i = 0; i < length; ++i)
            //     {
            //         sum += bytes[i];
            //     }
            //     return sum;
            // }
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(byte) }, typeof(Test));

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);       // stack: [length]
                il.Conv <UIntPtr>();
                il.Localloc();     // stack: [*pointer]
                var pointer = il.DeclareLocal(typeof(UIntPtr));
                il.Stloc(pointer); // pointer = value; stack: []

                il.Ldc_I4(0);      // stack: [0]
                var i = il.DeclareLocal(typeof(byte));
                il.Stloc(i);       // i = 0; stack: []
                var loop1Start = il.DefineLabel("loop1_start");
                var loop1End   = il.DefineLabel("loop1_end");
                il.MarkLabel(loop1Start);
                {
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldarg(0);                      // stack: [i, length]
                    il.Bge(loop1End, unsigned: true); // if (i >= length) goto end; stack: []
                    il.Ldloc(pointer);                //stack: [pointer]
                    il.Ldloc(i);                      // stack: [pointer, i]
                    il.Add();                         // stack: [pointer + i]
                    il.Ldloc(i);                      // stack: [pointer + i, i]
                    il.Stind(typeof(byte));           // *(pointer + i) = i; stack: []
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldc_I4(1);                     // stack: [i, 1]
                    il.Add();                         // stack: [i + 1]
                    il.Conv <byte>();
                    il.Stloc(i);                      // i = i + 1; stack: []
                    il.Br(loop1Start);
                }
                il.MarkLabel(loop1End);

                il.Ldc_I4(0);  // stack: [0]
                il.Dup();      // stack: [0, 0]
                var sum = il.DeclareLocal(typeof(int));
                il.Stloc(sum); // sum = 0; stack: [0]
                il.Stloc(i);   // i = 0; stack: []
                var loop2Start = il.DefineLabel("loop2_start");
                var loop2End   = il.DefineLabel("loop2_end");
                il.MarkLabel(loop2Start);
                {
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldarg(0);                      // stack: [i, length]
                    il.Bge(loop2End, unsigned: true); // if i >= length goto end; stack:[]
                    il.Ldloc(pointer);                // stack: [pointer]
                    il.Ldloc(i);                      // stack: [pointer, i]
                    il.Add();                         // stack: [pointer + i]
                    il.Ldind(typeof(byte));           // stack: [*(pointer + i)]
                    il.Ldloc(sum);                    // stack: [*(pointer + i), sum]
                    il.Add();                         // stack: [*(pointer + i) + sum]
                    il.Stloc(sum);                    // sum = *(pointer + i) + sum; stack: []
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldc_I4(1);                     // stack: [i, 1]
                    il.Add();                         // stack: [i + 1]
                    il.Conv <byte>();
                    il.Stloc(i);                      // i = (i + 1); // stack: []
                    il.Br(loop2Start);
                }
                il.MarkLabel(loop2End);

                il.Ldloc(sum); // stack: [sum]
                il.Ret();
            }
            var func = (Func <byte, int>)method.CreateDelegate(typeof(Func <byte, int>));

            Assert.That(func(6), Is.EqualTo(15));
        }
        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);
        }
예제 #18
0
        public void Test2()
        {
            AssemblyName myAssemblyName = new AssemblyName();

            myAssemblyName.Name = "AdderExceptionAsm";

            // Create dynamic assembly.
            AppDomain       myAppDomain       = Thread.GetDomain();
            AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName,
                                                                                  AssemblyBuilderAccess.RunAndSave);

            // Create a dynamic module.
            ModuleBuilder myModuleBuilder      = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true);
            var           symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty);

            TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder");

            Type[] adderParams = new Type[] { typeof(int), typeof(int) };

            ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor(
                new Type[] { typeof(string) });
            MethodInfo myExToStrMI   = typeof(OverflowException).GetMethod("ToString");
            MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) });

            // Define method to add two numbers.
            MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public |
                                                                       MethodAttributes.Static, typeof(int), adderParams);

            using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter))
            {
                // Declare local variable.
                GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int));
                GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException));

                // Define label.
                GroboIL.Label myFailedLabel      = il.DefineLabel("failed");
                GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end");

                // Begin exception block.
                il.BeginExceptionBlock();

                il.Ldarg(0);
                il.Ldc_I4(10);
                il.Bgt(myFailedLabel, false);

                il.Ldarg(1);
                il.Ldc_I4(10);
                il.Bgt(myFailedLabel, false);

                il.Ldarg(0);
                il.Ldarg(1);
                il.Add_Ovf(true);
                il.Stloc(myLocalBuilder1);
                il.Br(myEndOfMethodLabel);

                il.MarkLabel(myFailedLabel);
                il.Ldstr("Cannot accept values over 10 for add.");
                il.Newobj(myConstructorInfo);

                il.Stloc(myLocalBuilder2);
                il.Ldloc(myLocalBuilder2);

                // Throw the exception.
                il.Throw();

                // Call 'BeginExceptFilterBlock'.
                il.BeginExceptFilterBlock();
                il.WriteLine("Except filter block called.");

                // Call catch block.
                il.BeginCatchBlock(null);

                // Call other catch block.
                il.BeginCatchBlock(typeof(OverflowException));

                il.Ldstr("{0}");
                il.Ldloc(myLocalBuilder2);
                il.Call(myExToStrMI);
                il.Call(myWriteLineMI);
                il.Ldc_I4(-1);
                il.Stloc(myLocalBuilder1);

                // Call finally block.
                il.BeginFinallyBlock();
                il.WriteLine("Finally block called.");

                // End the exception block.
                il.EndExceptionBlock();

                il.MarkLabel(myEndOfMethodLabel);
                il.Ldloc(myLocalBuilder1);
                il.Ret();

                Console.WriteLine(il.GetILCode());
            }
        }
예제 #19
0
        private static Action <Hashtable, Array, int> EmitCopyValues()
        {
            /*
             * private void CopyValues(Hashtable hashtable, Array array, int arrayLength)
             * {
             *  bucket[] buckets = hashtable.buckets;
             *  int length = buckets.Length;
             *  int arrayIndex = 0;
             *  while (--length >= 0)
             *  {
             *      object key = buckets[length].key;
             *      if ((key != null) && (key != hashtable.buckets))
             *      {
             *          if (arrayIndex >= arrayLength)
             *              return;
             *          array.SetValue(buckets[length].val, arrayIndex++);
             *      }
             *  }
             * }
             */
            var dynamicMethod = new DynamicMethod(
                Guid.NewGuid().ToString(), typeof(void), new[] { typeof(Hashtable), typeof(Array), typeof(int) },
                typeof(Hashtable), true);

            var bucketsFieldInfo = typeof(Hashtable).GetField("buckets",
                                                              BindingFlags.Instance | BindingFlags.NonPublic);
            var bucketType      = typeof(Hashtable).GetNestedType("bucket", BindingFlags.NonPublic);
            var bucketArrayType = bucketType.MakeArrayType();

            var keyFieldInfo       = bucketType.GetField("key", BindingFlags.Instance | BindingFlags.Public);
            var valFieldInfo       = bucketType.GetField("val", BindingFlags.Instance | BindingFlags.Public);
            var setValueMethodInfo = typeof(Array).GetMethod("SetValue", new[] { typeof(object), typeof(int) });

            using (var il = new GroboIL(dynamicMethod))
            {
                var buckets    = il.DeclareLocal(bucketArrayType, "buckets");
                var length     = il.DeclareLocal(typeof(int), "length");
                var arrayIndex = il.DeclareLocal(typeof(int), "arrayIndex");
                var key        = il.DeclareLocal(typeof(object), "key");

                var cycleStartLabel = il.DefineLabel("cycleStart");
                var cycleNextLabel  = il.DefineLabel("cycleNext");
                var endLabel        = il.DefineLabel("end");

                il.EmitSetIntToZero(arrayIndex);

                il.Ldarg(0);                // stack: hashtable
                il.Ldfld(bucketsFieldInfo); // stack: hashtable::buckets
                il.Stloc(buckets);

                il.Ldloc(buckets);     // stack: hashtable::buckets
                il.Ldlen();            // stack: buckets.length
                il.Conv <int>();       // stack: buckets.length (i4)
                il.Stloc(length);
                il.Br(cycleNextLabel); // jump(cycleNext)

                il.MarkLabel(cycleStartLabel);

                il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: *bucket[current]

                il.Ldfld(keyFieldInfo);                               // stack: key
                il.Stloc(key);                                        // 2: key
                il.Ldloc(key);                                        // stack: key
                il.Brfalse(cycleNextLabel);                           // jump(cycleNext) if key == null
                il.Ldloc(key);                                        // stack: key
                il.Ldarg(0);                                          // stack+: hashtable
                il.Ldfld(bucketsFieldInfo);                           // stack: key, hashtable::buckets
                il.Beq(cycleNextLabel);
                // jump(cycleNext) if key == hashtable::buckets (какой-то хитрый хак hashtable-а)

                il.Ldloc(arrayIndex);                                 // stack: arrayIndex
                il.Ldarg(2);                                          // stack+: arrayLength
                il.Bge(endLabel, false);                              // jump(end) if arrayIndex >= arrayLength

                il.Ldarg(1);                                          // stack: array (arg1)

                il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: array (arg1), *bucket[current]
                il.Ldfld(valFieldInfo);                               // stack: array (arg1), bucket[current].val
                il.EmitXPlusPlus(arrayIndex);                         // stack: array (arg1), bucket[current].val, arrayIndex++

                il.Call(setValueMethodInfo);                          // array.SetValue(bucket[current].val, old_arrayIndex);

                il.MarkLabel(cycleNextLabel);

                il.EmitMinusMinusX(length);     // stack: --current
                il.Ldc_I4(0);                   // stack+: 0
                il.Bge(cycleStartLabel, false); // jump(cycleStart) if --current >= 0

                il.MarkLabel(endLabel);
                il.Ret();
            }

            return((Action <Hashtable, Array, int>)dynamicMethod.CreateDelegate(typeof(Action <Hashtable, Array, int>)));
        }
예제 #20
0
        public void Test1()
        {
            Type            overflow   = typeof(OverflowException);
            ConstructorInfo exCtorInfo = overflow.GetConstructor(
                new[] { typeof(string) });
            MethodInfo exToStrMI   = overflow.GetMethod("ToString");
            MethodInfo writeLineMI = typeof(Console).GetMethod("WriteLine",
                                                               new[]
            {
                typeof(string),
                typeof(object)
            });

            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int), typeof(int) }, typeof(TestTryCatch));

            using (var il = new GroboIL(method))
            {
                GroboIL.Local tmp1 = il.DeclareLocal(typeof(int));
                GroboIL.Local tmp2 = il.DeclareLocal(overflow);

                // In order to successfully branch, we need to create labels
                // representing the offset IL instruction block to branch to.
                // These labels, when the MarkLabel(Label) method is invoked,
                // will specify the IL instruction to branch to.
                //
                GroboIL.Label failed    = il.DefineLabel("failed");
                GroboIL.Label endOfMthd = il.DefineLabel("end");

                // Begin the try block.
                il.BeginExceptionBlock();

                // First, load argument 0 and the integer value of "100" onto the
                // stack. If arg0 > 100, branch to the label "failed", which is marked
                // as the address of the block that throws an exception.
                //
                il.Ldarg(0);
                il.Ldc_I4(100);
                il.Bgt(failed, false);

                // Now, check to see if argument 1 was greater than 100. If it was,
                // branch to "failed." Otherwise, fall through and perform the addition,
                // branching unconditionally to the instruction at the label "endOfMthd".
                //
                il.Ldarg(1);
                il.Ldc_I4(100);
                il.Bgt(failed, false);

                il.Ldarg(0);
                il.Ldarg(1);
                il.Add_Ovf(true);
                // Store the result of the addition.
                il.Stloc(tmp1);
                il.Br(endOfMthd);

                // If one of the arguments was greater than 100, we need to throw an
                // exception. We'll use "OverflowException" with a customized message.
                // First, we load our message onto the stack, and then create a new
                // exception object using the constructor overload that accepts a
                // string message.
                //
                il.MarkLabel(failed);
                il.Ldstr("Cannot accept values over 100 for add.");
                il.Newobj(exCtorInfo);

                // We're going to need to refer to that exception object later, so let's
                // store it in a temporary variable. Since the store function pops the
                // the value/reference off the stack, and we'll need it to throw the
                // exception, we will subsequently load it back onto the stack as well.

                il.Stloc(tmp2);
                il.Ldloc(tmp2);

                // Throw the exception now on the stack.

                il.Throw();

                // Start the catch block for OverflowException.
                //
                il.BeginCatchBlock(overflow);

                // When we enter the catch block, the thrown exception
                // is on the stack. Store it, then load the format string
                // for WriteLine.
                //
                il.Stloc(tmp2);
                il.Ldstr("Caught {0}");

                // Push the thrown exception back on the stack, then
                // call its ToString() method. Note that if this catch block
                // were for a more general exception type, like Exception,
                // it would be necessary to use the ToString for that type.
                //
                il.Ldloc(tmp2);
                il.Call(exToStrMI);

                // The format string and the return value from ToString() are
                // now on the stack. Call WriteLine(string, object).
                //
                il.Call(writeLineMI);

                // Since our function has to return an integer value, we'll load -1 onto
                // the stack to indicate an error, and store it in local variable tmp1.
                //
                il.Ldc_I4(-1);
                il.Stloc(tmp1);

                // End the exception handling block.

                il.EndExceptionBlock();

                // The end of the method. If no exception was thrown, the correct value
                // will be saved in tmp1. If an exception was thrown, tmp1 will be equal
                // to -1. Either way, we'll load the value of tmp1 onto the stack and return.
                //
                il.MarkLabel(endOfMthd);
                il.Ldloc(tmp1);
                il.Ret();

                Console.WriteLine(il.GetILCode());
            }
        }
예제 #21
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        private IQxx BuildSwitch(ModuleBuilder module, string[] keys)
        {
            var numberOfCases = keys.Length;
            var typeBuilder   = module.DefineType("Switch" + 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 tinyHashtable = Create(keys);
            var n             = tinyHashtable.Length;
            var keysField     = typeBuilder.DefineField("keys", typeof(string[]), FieldAttributes.Public);
            var constructor   = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(string[]) });

            using (var il = new GroboIL(constructor))
            {
                il.Ldarg(0);
                il.Ldarg(1);
                il.Stfld(keysField);
                il.Ret();
            }

            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))
            {
                il.Ldarg(0);
                il.Ldfld(keysField);
                il.Ldarg(1);
                il.Call(HackHelpers.GetMethodDefinition <object>(o => o.GetHashCode()));
                il.Ldc_I4(n);
                il.Rem(true);
                var idx = il.DeclareLocal(typeof(int));
                il.Dup();
                il.Stloc(idx);
                il.Ldelem(typeof(string));
                il.Ldarg(1);
                il.Call(stringEqualityOperator);
                var doneLabel = il.DefineLabel("done");
                il.Brfalse(doneLabel);

                var labels = new GroboIL.Label[n];
                for (var i = 0; i < n; ++i)
                {
                    labels[i] = doneLabel;
                }
                foreach (var key in keys)
                {
                    var index = key.GetHashCode() % n;
                    if (index < 0)
                    {
                        index += n;
                    }
                    var label = il.DefineLabel("set_" + key);
                    labels[index] = label;
                }
                il.Ldloc(idx);
                il.Switch(labels);
                for (var i = 0; i < keys.Length; ++i)
                {
                    var index = keys[i].GetHashCode() % n;
                    if (index < 0)
                    {
                        index += n;
                    }
                    il.MarkLabel(labels[index]);
                    il.Ldarg(0);
                    il.Ldarg(2);
                    il.Stfld(fields[i]);
                    il.Br(doneLabel);
                }
                il.MarkLabel(doneLabel);
                il.Ret();
            }
            typeBuilder.DefineMethodOverride(method, typeof(IQxx).GetMethod("Set"));
            var type = typeBuilder.CreateType();

            return((IQxx)Activator.CreateInstance(type, new object[] { tinyHashtable }));
        }
예제 #22
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(" ");
        }
예제 #23
0
        public void Test3()
        {
            // Create an assembly.
            AssemblyName myAssemblyName = new AssemblyName();

            myAssemblyName.Name = "AdderExceptionAsm";

            // Create dynamic assembly.
            AppDomain       myAppDomain       = Thread.GetDomain();
            AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName,
                                                                                  AssemblyBuilderAccess.Run);

            // Create a dynamic module.
            ModuleBuilder myModuleBuilder      = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true);
            var           symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty);
            TypeBuilder   myTypeBuilder        = myModuleBuilder.DefineType("Adder");

            Type[] myAdderParams = new Type[] { typeof(int), typeof(int) };

            // Create constructor.
            ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor(
                new Type[] { typeof(string) });
            MethodInfo myExToStrMI   = typeof(OverflowException).GetMethod("ToString");
            MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) });

            // Method to add two numbers.
            MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public |
                                                                       MethodAttributes.Static, typeof(int), myAdderParams);

            using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter))
            {
                // Declare local variable.
                GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int));
                GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException));

                // Define label.
                GroboIL.Label myFailedLabel      = il.DefineLabel("failed");
                GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end");

                // Begin exception block.
                il.BeginExceptionBlock();

                il.Ldarg(0);
                il.Ldc_I4(10);
                il.Bgt(myFailedLabel, false);

                il.Ldarg(1);
                il.Ldc_I4(10);
                il.Bgt(myFailedLabel, false);

                il.Ldarg(0);
                il.Ldarg(1);
                il.Add_Ovf(true);
                il.Stloc(myLocalBuilder1);
                il.Br(myEndOfMethodLabel);

                il.MarkLabel(myFailedLabel);
                il.Ldstr("Cannot accept values over 10 for addition.");
                il.Newobj(myConstructorInfo);

                il.Stloc(myLocalBuilder2);
                il.Ldloc(myLocalBuilder2);

                // Call fault block.
                il.BeginFaultBlock();
                //Throw exception.
                il.Newobj(typeof(NotSupportedException).GetConstructor(Type.EmptyTypes));
                il.Throw();

                // Call finally block.
                il.BeginFinallyBlock();

                il.Ldstr("{0}");
                il.Ldloc(myLocalBuilder2);
                il.Call(myExToStrMI);
                il.Call(myWriteLineMI);
                il.Ldc_I4(-1);
                il.Stloc(myLocalBuilder1);

                // End exception block.
                il.EndExceptionBlock();

                il.MarkLabel(myEndOfMethodLabel);
                il.Ldloc(myLocalBuilder1);
                il.Ret();

                Console.WriteLine(il.GetILCode());
            }

            Type adderType = myTypeBuilder.CreateType();

            object addIns = Activator.CreateInstance(adderType);

            object[] addParams = new object[2];

            addParams[0] = 20;

            addParams[1] = 10;

            Console.WriteLine("{0} + {1} = {2}",
                              addParams[0], addParams[1],
                              adderType.InvokeMember("DoAdd",
                                                     BindingFlags.InvokeMethod,
                                                     null,
                                                     addIns,
                                                     addParams));
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            Expression left = node.Left;
            Expression right = node.Right;
            Type       leftType, rightType;

            context.EmitLoadArgument(left, false, out leftType);
            context.EmitLoadArgument(right, false, out rightType);
            GroboIL il = context.Il;

            if (!leftType.IsNullable() && !rightType.IsNullable())
            {
                if (node.Method != null)
                {
                    il.Call(node.Method);
                }
                else
                {
                    if (leftType.IsStruct() || rightType.IsStruct())
                    {
                        throw new InvalidOperationException("Cannot compare structs");
                    }
                    il.Ceq();
                    if (node.NodeType == ExpressionType.NotEqual)
                    {
                        il.Ldc_I4(1);
                        il.Xor();
                    }
                }
            }
            else
            {
                var type = leftType;
                if (type != rightType)
                {
                    throw new InvalidOperationException("Cannot compare objects of different types '" + leftType + "' and '" + rightType + "'");
                }
                using (var localLeft = context.DeclareLocal(type))
                    using (var localRight = context.DeclareLocal(type))
                    {
                        il.Stloc(localRight);
                        il.Stloc(localLeft);
                        if (node.Method != null)
                        {
                            il.Ldloca(localLeft);             // stack: [&left]
                            context.EmitHasValueAccess(type); // stack: [left.HasValue]
                            il.Dup();                         // stack: [left.HasValue, left.HasValue]
                            il.Ldloca(localRight);            // stack: [left.HasValue, left.HasValue, &right]
                            context.EmitHasValueAccess(type); // stack: [left.HasValue, left.HasValue, right.HasValue]
                            var notEqualLabel = il.DefineLabel("notEqual");
                            il.Bne_Un(notEqualLabel);         // stack: [left.HasValue]
                            var equalLabel = il.DefineLabel("equal");
                            il.Brfalse(equalLabel);
                            il.Ldloca(localLeft);
                            context.EmitValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitValueAccess(type);
                            il.Call(node.Method);
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(notEqualLabel);
                            il.Pop();
                            il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 0 : 1);
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(equalLabel);
                            il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 1 : 0);
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                        }
                        else
                        {
                            il.Ldloca(localLeft);
                            context.EmitValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitValueAccess(type);
                            var notEqualLabel = il.DefineLabel("notEqual");
                            il.Bne_Un(notEqualLabel);
                            il.Ldloca(localLeft);
                            context.EmitHasValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitHasValueAccess(type);
                            il.Ceq();
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(notEqualLabel);
                            il.Ldc_I4(0);
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            if (node.NodeType == ExpressionType.NotEqual)
                            {
                                il.Ldc_I4(1);
                                il.Xor();
                            }
                        }
                    }
            }
            resultType = typeof(bool);
            return(false);
        }
        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);
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL il = context.Il;

            if (node.Method != null)
            {
                throw new NotSupportedException("Custom operator '" + node.NodeType + "' is not supported");
            }
            Expression left  = node.Left;
            Expression right = node.Right;
            Type       leftType;

            context.EmitLoadArgument(left, false, out leftType); // stack: [left]
            if (leftType == typeof(bool))
            {
                switch (node.NodeType)
                {
                case ExpressionType.AndAlso:
                {
                    var returnFalseLabel = il.DefineLabel("returnFalse");
                    il.Brfalse(returnFalseLabel);                          // if(left == false) return false; stack: []
                    Type rightType;
                    context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);                                      // goto done; stack: [right]
                    context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                    il.Ldc_I4(0);                                          // stack: [false]
                    if (rightType == typeof(bool?))
                    {
                        il.Newobj(nullableBoolConstructor);     // stack: [new bool?(false)]
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                    resultType = rightType;
                    break;
                }

                case ExpressionType.OrElse:
                {
                    var returnTrueLabel = il.DefineLabel("returnTrue");
                    il.Brtrue(returnTrueLabel);                            // if(left == true) return true; stack: []
                    Type rightType;
                    context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);                                      // goto done; stack: [right]
                    context.MarkLabelAndSurroundWithSP(returnTrueLabel);
                    il.Ldc_I4(1);                                          // stack: [true]
                    if (rightType == typeof(bool?))
                    {
                        il.Newobj(nullableBoolConstructor);     // stack: [new bool?(true)]
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                    resultType = rightType;
                    break;
                }

                default:
                    throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported");
                }
            }
            else // bool?
            {
                switch (node.NodeType)
                {
                case ExpressionType.AndAlso:
                {
                    /*
                     * +-------+-------+-------+-------+
                     * |  &&   | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | null  | null  | false | null  |
                     * +-------+-------+-------+-------+
                     * | false | false | false | false |
                     * +-------+-------+-------+-------+
                     * | true  | null  | false | true  |
                     * +-------+-------+-------+-------+
                     */
                    using (var localLeft = context.DeclareLocal(typeof(bool?)))
                    {
                        il.Stloc(localLeft);                                   // localLeft = left; stack: []
                        il.Ldloca(localLeft);                                  // stack: [&localLeft]
                        context.EmitHasValueAccess(typeof(bool?));             // stack: [localLeft.HasValue]
                        il.Ldc_I4(1);                                          // stack: [localLeft.HasValue, true]
                        il.Xor();                                              // stack: [!localLeft.HasValue]
                        il.Ldloca(localLeft);                                  // stack: [!localLeft.HasValue, &localLeft]
                        context.EmitValueAccess(typeof(bool?));                // stack: [!localLeft.HasValue, localLeft.Value]
                        il.Or();                                               // stack: [!localLeft.HasValue || localLeft.Value]
                        var returnFalseLabel = il.DefineLabel("returnFalse");
                        il.Brfalse(returnFalseLabel);                          // if(localLeft == false) goto returnFalse; stack: []
                        Type rightType;
                        context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                        using (var localRight = context.DeclareLocal(rightType))
                        {
                            il.Stloc(localRight);     // localRight = right; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldc_I4(1);                              // stack: [localRight.HasValue, true]
                                il.Xor();                                  // stack: [!localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [!localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [!localRight.HasValue, localRight.Value]
                                il.Or();                                   // stack: [!localRight.HasValue || localRight.Value]
                            }
                            il.Brfalse(returnFalseLabel);                  // if(localRight == false) goto returnFalse;
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [localRight.HasValue, localRight.Value]
                                il.And();                                  // stack: [localRight.HasValue && localRight.Value]
                            }
                            var returnLeftLabel = il.DefineLabel("returnLeft");
                            il.Brtrue(returnLeftLabel); // if(localRight == true) goto returnLeft;
                            il.Ldloca(localLeft);       // stack: [&localLeft]
                            il.Initobj(typeof(bool?));  // localLeft = default(bool?); stack: []
                            context.MarkLabelAndSurroundWithSP(returnLeftLabel);
                            il.Ldloc(localLeft);        // stack: [localLeft]
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                            il.Ldc_I4(0);                       // stack: [false]
                            il.Newobj(nullableBoolConstructor); // new bool?(false)
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            resultType = typeof(bool?);
                        }
                    }
                    break;
                }

                case ExpressionType.OrElse:
                {
                    /*
                     * +-------+-------+-------+-------+
                     * |  ||   | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | null  | null  | null  | true  |
                     * +-------+-------+-------+-------+
                     * | false | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | true  | true  | true  | true  |
                     * +-------+-------+-------+-------+
                     */
                    using (var localLeft = context.DeclareLocal(typeof(bool?)))
                    {
                        il.Stloc(localLeft);                                   // localLeft = left; stack: []
                        il.Ldloca(localLeft);                                  // stack: [&localLeft]
                        context.EmitHasValueAccess(typeof(bool?));             // stack: [localLeft.HasValue]
                        il.Ldloca(localLeft);                                  // stack: [localLeft.HasValue, &localLeft]
                        context.EmitValueAccess(typeof(bool?));                // stack: [localLeft.HasValue, localLeft.Value]
                        il.And();                                              // stack: [localLeft.HasValue && localLeft.Value]
                        var returnTrueLabel = il.DefineLabel("returnTrue");
                        il.Brtrue(returnTrueLabel);                            // if(localLeft == true) goto returnTrue; stack: []
                        Type rightType;
                        context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                        using (var localRight = context.DeclareLocal(rightType))
                        {
                            il.Stloc(localRight);     // localRight = right; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [localRight.HasValue, localRight.Value]
                                il.And();                                  // stack: [localRight.HasValue && localRight.Value]
                            }
                            il.Brtrue(returnTrueLabel);                    // if(localRight == true) goto returnTrue; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldc_I4(1);                              // stack: [localRight.HasValue, true]
                                il.Xor();                                  // stack: [!localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [!localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [!localRight.HasValue, localRight.Value]
                                il.Or();                                   // stack: [!localRight.HasValue || localRight.Value]
                            }
                            var returnLeftLabel = il.DefineLabel("returnLeft");
                            il.Brfalse(returnLeftLabel); // if(localRight == false) goto returnLeft;
                            il.Ldloca(localLeft);        // stack: [&localLeft]
                            il.Initobj(typeof(bool?));   // localLeft = default(bool?); stack: []
                            context.MarkLabelAndSurroundWithSP(returnLeftLabel);
                            il.Ldloc(localLeft);         // stack: [localLeft]
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(returnTrueLabel);
                            il.Ldc_I4(1);                       // stack: [true]
                            il.Newobj(nullableBoolConstructor); // new bool?(true)
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            resultType = typeof(bool?);
                        }
                    }
                    break;
                }

                default:
                    throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported");
                }
            }
            return(false);
        }