예제 #1
0
        public static TryGetValueDelegate <T> Build <T>(string[] keys, T[] values)
        {
            var trie   = BuildTrie(keys);
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(T[]), typeof(string), typeof(T).MakeByRefType() },
                                           typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(2);                 // stack: [ref value]
                il.Initobj(typeof(T));       // value = default(value); stack: []
                var index = il.DeclareLocal(typeof(int), "index");
                il.Ldc_I4(0);                // stack: [0]
                il.Stloc(index);             // index = 0; stack: []
                var length = il.DeclareLocal(typeof(int), "length");
                il.Ldarg(1);                 // stack: [key]
                il.Call(stringLengthGetter); // stack: [key.Length]
                il.Stloc(length);            // length = key.Length; stack: []
                var context = new EmittingContext
                {
                    Il      = il,
                    Index   = index,
                    Length  = length,
                    CurChar = il.DeclareLocal(typeof(char))
                };
                InlineTrie <T>(trie, context);
            }
            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), values));
        }
        protected override bool EmitInternal(NewExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            context.EmitLoadArguments(node.Arguments.ToArray());
            // note ich: баг решарпера
            // ReSharper disable ConditionIsAlwaysTrueOrFalse
            // ReSharper disable HeuristicUnreachableCode
            GroboIL il = context.Il;

            if (node.Constructor != null)
            {
                il.Newobj(node.Constructor);
            }
            else
            {
                if (node.Type.IsValueType)
                {
                    using (var temp = context.DeclareLocal(node.Type))
                    {
                        il.Ldloca(temp);
                        il.Initobj(node.Type);
                        il.Ldloc(temp);
                    }
                }
                else
                {
                    throw new InvalidOperationException("Missing constructor for type '" + node.Type + "'");
                }
            }
            resultType = node.Type;
            // ReSharper restore ConditionIsAlwaysTrueOrFalse
            // ReSharper restore HeuristicUnreachableCode
            return(false);
        }
예제 #3
0
        public static TryGetValueDelegate <T> Build <T>(string[] keys, T[] values, Func <string, int> hashCodeEvaluator)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(Closure <T>), typeof(string), typeof(T).MakeByRefType() }, typeof(string), true);
            var hashCodes = keys.Select(hashCodeEvaluator).ToArray();
            int n         = keys.Length;
            var indexes   = new int[n];

            for (int i = 0; i < n; ++i)
            {
                indexes[i] = i;
            }
            Array.Sort(indexes, (lhs, rhs) => hashCodes[lhs].CompareTo(hashCodes[rhs]));
            using (var il = new GroboIL(method))
            {
                var retFalseLabel = il.DefineLabel("retFalse");
                var hashCode      = il.DeclareLocal(typeof(int), "hashCode");
                il.Ldarg(0);                                                                                          // stack: [closure]
                il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.hashCodeEvaluator));                              // stack: [closure.hashCodeEvaluator]
                il.Ldarg(1);                                                                                          // stack: [closure.hashCodeEvaluator, key]
                il.Call(typeof(Func <string, int>).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public)); // stack: [closure.hashCodeEvaluator(key)]
                il.Stloc(hashCode);                                                                                   // hashCode = closure.hashCodeEvaluator(key); stack: []

                var context = new EmittingContext
                {
                    Il            = il,
                    Keys          = keys,
                    HashCodes     = hashCodes,
                    Indexes       = indexes,
                    HashCode      = hashCode,
                    RetFalseLabel = retFalseLabel
                };
                DoBinarySearch <T>(context, 0, n - 1);
                il.MarkLabel(retFalseLabel);
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            var closure = new Closure <T>
            {
                hashCodeEvaluator = hashCodeEvaluator,
                values            = values
            };

            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure));
        }
예제 #4
0
        // todo: kill
        private KeyValuePair <Delegate, IntPtr> BuildDefaultValueReader(ModuleBuilder module)
        {
            var method = new DynamicMethod("Default_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(1);      // stack: [ref result]
                il.Initobj(Type); // [result = default(T)]
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
        private static void EmitDefaultTypeValue(GroboIL il, Type type)
        {
            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.Boolean:
            case TypeCode.Char:
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
                il.Ldc_I4(0);
                return;

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

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

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

            if (type.IsPointer || type == typeof(UIntPtr) || type == typeof(IntPtr))
            {
                il.Ldc_IntPtr(IntPtr.Zero);
                il.Conv <UIntPtr>();
            }
            else if (type.IsEnum)
            {
                EmitDefaultTypeValue(il, Enum.GetUnderlyingType(type));
            }
            else if (type.IsValueType)
            {
                var local = il.DeclareLocal(type);
                il.Ldloca(local);
                il.Initobj(type);
                il.Ldloc(local);
            }
            else
            {
                il.Ldnull();
            }
        }
예제 #6
0
        public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values)
        {
            // Assuming keys are sorted
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(T[]), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true);
            //var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("zzz"), AssemblyBuilderAccess.RunAndSave);
            //var module = assembly.DefineDynamicModule("qxx", "zzz.dll");
            //var typeBuilder = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public);
            //var method = typeBuilder.DefineMethod("do_switch", MethodAttributes.Public | MethodAttributes.Static,
            //                                      typeof(bool), new[] {typeof(T[]), typeof(char), typeof(T).MakeByRefType()});
            int n = keys.Length;

            using (var il = new GroboIL(method))
            {
                var retFalseLabel = il.DefineLabel("retFalse");
                var context       = new EmittingContext
                {
                    Il            = il,
                    Keys          = keys,
                    RetFalseLabel = retFalseLabel
                };
                DoBinarySearch <T>(context, 0, n - 1);
                il.MarkLabel(retFalseLabel);
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            //typeBuilder.CreateType();
            //assembly.Save("zzz.dll");
            //return null;
            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), values));
        }
예제 #7
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());
            }
        }
예제 #8
0
        public static TryGetValueDelegate <T> Build <T>(string[] keys, T[] values)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(T[]), typeof(string), typeof(T).MakeByRefType() }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                for (int i = 0; i < keys.Length; ++i)
                {
                    il.Ldarg(1);                     // stack: [key]
                    il.Ldstr(keys[i]);               // stack: [key, keys[i]]
                    var nextKeyLabel = il.DefineLabel("nextKey");
                    il.Call(stringEqualityOperator); // stack: [key == keys[i]]
                    il.Brfalse(nextKeyLabel);        // if(key != keys[i]) goto nextKey; stack: []
                    il.Ldarg(2);                     // stack: [ref value]
                    il.Ldarg(0);                     // stack: [ref value, values]
                    il.Ldc_I4(i);                    // stack: [ref value, values, i]
                    il.Ldelem(typeof(T));            // stack: [ref value, values[i]]
                    il.Stind(typeof(T));             // value = values[i]; stack: []
                    il.Ldc_I4(1);                    // stack: [true]
                    il.Ret();
                    il.MarkLabel(nextKeyLabel);
                }
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), values));
        }
예제 #9
0
        private KeyValuePair <Delegate, IntPtr> GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member)
        {
            var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, context.Module, true);

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

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

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

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

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
예제 #10
0
        public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true);
            var indices = new List <int>();

            using (var il = new GroboIL(method))
            {
                var idx           = il.DeclareLocal(typeof(int), "idx");
                var retFalseLabel = il.DefineLabel("retFalse");
                for (int i = 0; i < numberOfSegments; ++i)
                {
                    var firstKeyInSegment = keys[i * numberOfKeysPerSegment];
                    var lastKeyInSegment  = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment];
                    il.Ldarg(1);                                                   // stack: [key]
                    il.Ldc_I4(firstKeyInSegment);                                  // stack: [key, firstKey]
                    var nextSegmentLabel = il.DefineLabel("nextSegment");
                    il.Blt(nextSegmentLabel, false);                               // if(key < firstKey) goto nextSegment; stack: []
                    il.Ldarg(1);                                                   // stack: [key]
                    il.Ldc_I4(lastKeyInSegment);                                   // stack: [key, lastKey]
                    il.Bgt(nextSegmentLabel, false);                               // if(key > lastKey) goto nextSegment; stack: []
                    il.Ldarg(0);                                                   // stack: [closure]
                    il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.indices)); // stack: [closure.indices]
                    il.Ldarg(1);                                                   // stack: [closure.indices, key]
                    il.Ldc_I4(firstKeyInSegment - indices.Count);                  // stack: [closure.indices, key, diff]
                    il.Sub();                                                      // stack: [closure.indices, key - diff]
                    il.Ldelem(typeof(int));                                        // stack: [closure.indices[key - diff]]
                    il.Dup();
                    il.Stloc(idx);                                                 // idx = closure.indices[key - diff]; stack: [idx]
                    il.Ldc_I4(0);                                                  // stack: [idx, 0]
                    il.Blt(retFalseLabel, false);                                  // if(idx < 0) goto retFalse; stack: []
                    il.Ldarg(2);                                                   // stack: [ref value]
                    il.Ldarg(0);                                                   // stack: [ref value, closure]
                    il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.values));  // stack: [ref value, closure.values]
                    il.Ldloc(idx);                                                 // stack: [ref value, closure.values, idx]
                    il.Ldelem(typeof(T));                                          // stack: [ref value, closure.values[idx]]
                    il.Stind(typeof(T));                                           // value = closure.values[idx]; stack: []
                    il.Ldc_I4(1);                                                  // stack: [true]
                    il.Ret();
                    il.MarkLabel(nextSegmentLabel);
                    var segmentLength = lastKeyInSegment - firstKeyInSegment + 1;
                    int start         = indices.Count;
                    for (int j = 0; j < segmentLength; ++j)
                    {
                        indices.Add(-1);
                    }
                    for (int j = 0; j < numberOfKeysPerSegment; ++j)
                    {
                        indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j;
                    }
                }
                il.MarkLabel(retFalseLabel);
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            var closure = new Closure <T>
            {
                indices = indices.ToArray(),
                values  = values
            };

            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure));
        }
예제 #11
0
        public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment)
        {
            // Assuming keys are sorted
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true);
            var indices = new List <int>();

            using (var il = new GroboIL(method))
            {
                var idx           = il.DeclareLocal(typeof(int), "idx");
                var retFalseLabel = il.DefineLabel("retFalse");
                var segments      = new Segment[numberOfSegments];
                for (int i = 0; i < numberOfSegments; ++i)
                {
                    var firstKeyInSegment = keys[i * numberOfKeysPerSegment];
                    var lastKeyInSegment  = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment];
                    segments[i] = new Segment
                    {
                        FirstKey = firstKeyInSegment,
                        LastKey  = lastKeyInSegment,
                        Diff     = firstKeyInSegment - indices.Count
                    };
                    var segmentLength = lastKeyInSegment - firstKeyInSegment + 1;
                    int start         = indices.Count;
                    for (int j = 0; j < segmentLength; ++j)
                    {
                        indices.Add(-1);
                    }
                    for (int j = 0; j < numberOfKeysPerSegment; ++j)
                    {
                        indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j;
                    }
                }
                var context = new EmittingContext
                {
                    Il            = il,
                    Segments      = segments,
                    RetFalseLabel = retFalseLabel,
                    Idx           = idx
                };
                DoBinarySearch <T>(context, 0, numberOfSegments - 1);
                il.MarkLabel(retFalseLabel);
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            var closure = new Closure <T>
            {
                indices = indices.ToArray(),
                values  = values
            };

            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure));
        }
        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);
        }