예제 #1
0
        private void TestSuccess(Type type1, Type type2)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { type1, type2, }.Where(type => type != null).ToArray(), typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var index = 0;
                if (type1 != null)
                {
                    il.Ldarg(index++);
                }
                else
                {
                    il.Ldnull();
                }
                if (type2 != null)
                {
                    il.Ldarg(index++);
                }
                else
                {
                    il.Ldnull();
                }
                il.Xor();
                il.Pop();
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
        }
예제 #2
0
        private Func <TestClassA, int> Build1()
        {
            var typeBuilder = Module.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Class | TypeAttributes.Public);
            var method      = typeBuilder.DefineMethod("zzz", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(TestClassA) });

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                il.Ldfld(typeof(TestClassA).GetField("Y"));
                var y = il.DeclareLocal(typeof(int));
                il.Stloc(y);
                il.Ldarg(0);
                il.Ldfld(typeof(TestClassA).GetField("Z"));
                var z = il.DeclareLocal(typeof(int));
                il.Stloc(z);
                il.Ldloc(y);
                il.Ldloc(z);
                il.Add();
                il.Ret();
            }
            var type          = typeBuilder.CreateType();
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(Func <TestClassA, int>), Type.EmptyTypes, Module, true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldnull();
                il.Ldftn(type.GetMethod("zzz"));
                il.Newobj(typeof(Func <TestClassA, int>).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
                il.Ret();
            }
            return(((Func <Func <TestClassA, int> >)dynamicMethod.CreateDelegate(typeof(Func <Func <TestClassA, int> >)))());
        }
예제 #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));
        }
        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();
            }
        }
예제 #5
0
            private static Func <Type, bool> BuildIsATypeBuilderInstChecker()
            {
                var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Type) }, typeof(ReflectionExtensions), true);

                using (var il = new GroboIL(dynamicMethod))
                {
                    il.Ldarg(0);
                    il.Isinst(typeBuilderInstType);
                    il.Ldnull();
                    il.Cgt(true);
                    il.Ret();
                }
                return((Func <Type, bool>)dynamicMethod.CreateDelegate(typeof(Func <Type, bool>)));
            }
예제 #6
0
        private void TestFailure(Type type1, Type type2)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { type1, type2, }.Where(type => type != null).ToArray(), typeof(string), true);
            var il     = new GroboIL(method);
            var index  = 0;

            if (type1 != null)
            {
                il.Ldarg(index++);
            }
            else
            {
                il.Ldnull();
            }
            if (type2 != null)
            {
                il.Ldarg(index++);
            }
            else
            {
                il.Ldnull();
            }
            Assert.Throws <InvalidOperationException>(il.Xor);
        }
예제 #7
0
        protected TDelegate CompileToMethod <TDelegate>(Expression <TDelegate> lambda, CompilerOptions options) where TDelegate : class
        {
            var typeBuilder = TestPerformance.Module.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Public);
            var method      = typeBuilder.DefineMethod("lambda", MethodAttributes.Public | MethodAttributes.Static, lambda.ReturnType, lambda.Parameters.Select(parameter => parameter.Type).ToArray());

            LambdaCompiler.CompileToMethod(lambda, method, options);
            var type          = typeBuilder.CreateType();
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(TDelegate), null, TestPerformance.Module, true);

            using (var il = new GroboIL(dynamicMethod))
            {
                il.Ldnull();
                il.Ldftn(type.GetMethod("lambda"));
                il.Newobj(typeof(TDelegate).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
                il.Ret();
            }
            return(((Func <TDelegate>)dynamicMethod.CreateDelegate(typeof(Func <TDelegate>)))());
        }
예제 #8
0
        public static void WriteObjectNull(GroboIL il, GroboIL.Label finishMethod, GroboIL.Local buffer, GroboIL.Local offset, GroboIL.Local typeSize)
        {
            var _null = il.DeclareLocal(typeof(bool));

            il.Ldnull();
            il.Ceq();
            il.Stloc(_null);

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

            il.Ldloc(_null);

            il.Stelem(typeof(byte));

            WriteOffsetAppend(il, offset, 1);

            il.Ldloc(_null);
            il.Brtrue(finishMethod);
        }
예제 #9
0
        private static void BuildJump(TypeBuilder typeBuilder, int n, Context context)
        {
            var method = typeBuilder.DefineMethod("Jump", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(MethodCallNode), new[] { typeof(int) });

            using (var il = new GroboIL(method))
            {
                var retNullLabel    = il.DefineLabel("retNull");
                var emittingContext = new MethodJumpEmittingContext
                {
                    context      = context,
                    il           = il,
                    retNullLabel = retNullLabel
                };
                DoBinarySearch(emittingContext, 0, n - 1);
                il.MarkLabel(retNullLabel);
                il.Ldnull();
                il.Ret();
            }
            typeBuilder.DefineMethodOverride(method, typeof(MethodCallNodeEdges).GetMethod(method.Name, BindingFlags.Public | BindingFlags.Instance));
        }
예제 #10
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));
        }
예제 #11
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));
        }
예제 #12
0
        private static EnumParserDelegate EmitEnumParser()
        {
            var method         = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(Type), typeof(string), typeof(bool) }, typeof(string), true);
            var il             = new GroboIL(method);
            var enumResultType = typeof(Enum).GetNestedType("EnumResult", BindingFlags.NonPublic);
            var enumResult     = il.DeclareLocal(enumResultType);

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

            il.Brfalse(returnNullLabel);
            il.Ldloca(enumResult);
            il.Ldfld(enumResultType.GetField("parsedEnum", BindingFlags.Instance | BindingFlags.NonPublic));
            il.Ret();
            il.MarkLabel(returnNullLabel);
            il.Ldnull();
            il.Ret();
            return((EnumParserDelegate)method.CreateDelegate(typeof(EnumParserDelegate)));
        }
예제 #13
0
        private static Type BuildTypeInternal(Type type)
        {
            var parentType  = typeof(ValidationResultTreeNode);
            var properties  = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var typeBuilder = module.DefineType(type.Name + "_" + id++, TypeAttributes.Class | TypeAttributes.Public, parentType);

            typesBeingBuilt[type] = typeBuilder;

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

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

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

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

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

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

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

            typeBuilder.DefineMethodOverride(getChildrenMethodBuilder, getChildrenMethod);

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

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

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

            typeBuilder.DefineMethodOverride(traverseEdgeMethodBuilder, traverseEdgeMethod);

            var result = typeBuilder.CreateTypeInfo();

            typesBeingBuilt[type] = null;
            return(result);
        }
예제 #14
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));
        }
예제 #15
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));
        }