예제 #1
0
 private static void EmitBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
 {
     // a.Property == b.Property
     il.Ldarg(0);
     il.Call(getMethod);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Bne_Un(returnFalse);
 }
예제 #2
0
 private static void EmitInstance(GroboIL il, MethodInfo getMethod, MethodInfo instanceMethod, GroboIL.Label returnFalse)
 {
     // a.Property.Equals(b.Property)
     var type = getMethod.ReturnType;
     var local = il.DeclareLocal(type);
     il.Ldarg(0);
     il.Call(getMethod);
     il.Stloc(local);
     il.Ldloca(local);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Call(instanceMethod, type);
     il.Brfalse(returnFalse);
 }
예제 #3
0
 private static void EmitNullableEquals(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
 {
     // a.Equals(b)
     var type = getMethod.ReturnType;
     var local = il.DeclareLocal(type);
     il.Ldarg(0);
     il.Call(getMethod);
     il.Stloc(local);
     il.Ldloca(local);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Box(type);
     il.Call(ObjectEquals, type);
     il.Brfalse(returnFalse);
 }
예제 #4
0
 private static void EmitStatic(GroboIL il, MethodInfo getMethod, MethodInfo staticMethod, GroboIL.Label returnFalse)
 {
     // Equals(a.Property, b.Property)
     il.Ldarg(0);
     il.Call(getMethod);
     il.Ldarg(1);
     il.Call(getMethod);
     il.Call(staticMethod);
     il.Brfalse(returnFalse);
 }
예제 #5
0
        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 }));
        }
예제 #6
0
        private static void EmitNullableBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse)
        {
            // a.GetValueOrDefault() == b.GetValueOrDefault() && a.HasValue == b.HasValue;
            var type = getMethod.ReturnType;
            var getValueOrDefault = type.GetMethod("GetValueOrDefault", new Type[0]);
            var hasValue = type.GetMethod("get_HasValue");
            var a = il.DeclareLocal(type);
            var b = il.DeclareLocal(type);

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

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

            il.Ldloca(a);
            il.Call(hasValue);
            il.Ldloca(b);
            il.Call(hasValue);
            il.Bne_Un(returnFalse);
        }
예제 #7
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var exitLabel = il.DefineLabel("exit");

            BinaryStruct.WriteSizeChecker(il, buffer, offset, 4);

            var arr = il.DeclareLocal(typeof(byte[]));

            il.Ldarg(1);
            il.Call(codingMethodInfo);
            il.Ldloc(value);

            if (!listValue)
            {
                il.Call(prop.Getter);
            }

            il.Dup();
            BinaryStruct.WriteObjectNull(il, exitLabel, buffer, offset, typeSize);

            il.Call(currentStruct.Coding.GetType().GetMethod("GetBytes", new Type[] { typeof(string) }));
            il.Stloc(arr);


            if (prop.PropertyInfo != null)
            {
                il.Ldloc(value);
                il.Call(prop.TypeSizeProperty.Getter);
                il.Stloc(typeSize);
            }
            else
            {
                il.Ldc_I4(prop.TypeSize);
                il.Stloc(typeSize);
            }

            BinaryStruct.WriteSizeChecker(il, buffer, offset, typeSize);

            var ivar  = il.DeclareLocal(typeof(int));
            var point = il.DefineLabel("for_label");

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

            il.MarkLabel(point);

            //body

            il.Ldloc(buffer);
            il.Ldloc(ivar);
            il.Ldloc(offset);
            il.Add();
            il.Ldloc(arr);
            il.Ldloc(ivar);

            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            //end body

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

            il.Ldloc(ivar);
            il.Ldloc(typeSize);

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

            BinaryStruct.WriteOffsetAppend(il, offset, typeSize);
        }
예제 #8
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));
        }
예제 #9
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(" ");
        }
예제 #10
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(" ");
        }
예제 #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));
        }
예제 #12
0
        /// <summary>
        /// Builds Proxy Type that implement an interface, and proxy calls to defined with attribute
        /// methods via defined intercepting handlers
        /// </summary>
        /// <param name="interface">Type to wrap</param>
        /// <param name="implementation">
        /// Type providing interface implementation, intercepting attributes are read from this type
        /// </param>
        /// <returns>
        /// Proxy type with constructor accepting object implementing @interface and intercepting
        /// handlers as parameters
        /// </returns>
        public static Type CreateInterfaceProxy(Type @interface, Type implementation)
        {
            Contract.Ensures(Contract.Result <Type>() != null);
            if ([email protected])
            {
                throw new ArgumentException($"{nameof(@interface)} ({@interface.FullName}) is not an interface.");
            }

            if ([email protected](implementation))
            {
                throw new ArgumentException($"{nameof(@interface)} ({@interface.FullName}) is not assignable from {nameof(implementation)} ({implementation.FullName})");
            }
            var typeName    = $"{@interface.Assembly.GetName().Name}.v{@interface.Assembly.GetName().Version}.{@interface.FullName}";
            var typeBuilder = ModuleBuilder.DefineType($"InterceptorProxy_{typeName}_{Guid.NewGuid().ToString("N")}", TypeAttributes.Class | TypeAttributes.Public);

            typeBuilder.AddInterfaceImplementation(SetupGenericClassArguments(@interface, typeBuilder));

            var methods = new List <MethodPair>();

            AddMethodPairsToList(methods, @interface, implementation);

            var methodInterceptors = new Dictionary <MethodInfo, Type[]>();
            var interceptorFields  = new Dictionary <Type, FieldInfo>();

            var methodsCount      = methods.Count;
            var attributesHashSet = new HashSet <Type>();

            for (var i = 0; i < methodsCount; i++)
            {
                var method          = methods[i];
                var interfaceMethod = method.InterfaceMethod;
                var typeMethod      = method.TargetMethod;

                var attributeTypes = Attribute.GetCustomAttributes(typeMethod, typeof(InterceptorAttribute), true)
                                     .OrderBy(a => ((InterceptorAttribute)a).Order).Select(a => ((InterceptorAttribute)a).InterceptionHandlerType).ToArray();

                for (int j = 0; j < attributeTypes.Length; j++)
                {
                    if (!typeof(IInterceptionHandler).IsAssignableFrom(attributeTypes[j]))
                    {
                        throw new InvalidOperationException($"Interception handler type should implement {nameof(IInterceptionHandler)} interface");
                    }
                }

                attributesHashSet.UnionWith(attributeTypes);
                methodInterceptors.Add(interfaceMethod, attributeTypes);
            }

            var baseConstructorInfo = typeof(object).GetConstructor(Type.EmptyTypes);

            var intercpetionHandlerType = typeof(IInterceptionHandler);

            var genericInterceptionAction = intercpetionHandlerType.GetMethods().Single(i => i.Name == "InterceptingAction" && i.ReturnType != typeof(void));
            var voidInterceptionAction    = intercpetionHandlerType.GetMethods().Single(i => i.Name == "InterceptingAction" && i.ReturnType == typeof(void));

            var att = attributesHashSet.ToList();

            att.Insert(0, implementation);
            var paramArray = att.ToArray();

            var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, paramArray);
            var concrete           = typeBuilder.DefineField("Concrete", @interface, FieldAttributes.Public);

            for (int i = 1; i < paramArray.Length; i++)
            {
                var at = paramArray[i];
                interceptorFields.Add(at, typeBuilder.DefineField(at.Name, intercpetionHandlerType, FieldAttributes.Public));
            }

            GroboIL il;

            using (il = new GroboIL(constructorBuilder))
            {
                il.Ldarg(0);
                il.Call(baseConstructorInfo);
                il.Nop();

                // set concrete
                il.Ldarg(0);
                il.Ldarg(1);
                il.Stfld(concrete);

                // set injected interceptionHandlers
                for (var i = 1; i < paramArray.Length; i++)
                {
                    il.Ldarg(0);
                    il.Ldarg(i + 1);
                    il.Stfld(interceptorFields[paramArray[i]]);
                }

                il.Ret();

                LogIlCode(il);
            }

            for (var i = 0; i < methodsCount; i++)
            {
                var interfaceMethod = methods[i].InterfaceMethod;

                if (interfaceMethod.IsGenericMethod)
                {
                    interfaceMethod = interfaceMethod.GetGenericMethodDefinition();
                }

                DefineMethodOverride(typeBuilder, interfaceMethod, methodInterceptors, interceptorFields, genericInterceptionAction, voidInterceptionAction, concrete);
            }

            return(typeBuilder.CreateTypeInfo().AsType());
        }
예제 #13
0
        private static MethodBuilder GenerateOverloadedMethodDelegate(MethodInfo methodToIntercept,
                                                                      TypeBuilder typeBuilder,
                                                                      FieldInfo concrete)
        {
            // Define the method
            var method = typeBuilder.DefineMethod(methodToIntercept.Name + "-Delegate",
                                                  MethodAttributes.Private | MethodAttributes.HideBySig,
                                                  methodToIntercept.ReturnType,
                                                  new[] { typeof(ParamInfo[]) });

            SetupGenericMethodArguments(methodToIntercept, method);

            // Local for each out/ref parameter
            var parameters = methodToIntercept.GetParameters();

            var locals = new Dictionary <string, Local>();

            using (var il = new GroboIL(method))
            {
                foreach (ParameterInfo parameter in parameters)
                {
                    if (parameter.IsOut || parameter.ParameterType.IsByRef)
                    {
                        locals.Add(parameter.Name, il.DeclareLocal(parameter.ParameterType.GetElementType(), parameter.Name));
                    }
                }

                var paramInfoType     = typeof(ParamInfo);
                var paramInfoGetValue = paramInfoType.GetProperty("Value").GetGetMethod();

                // Initialize out parameters to default values
                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].ParameterType.IsByRef && !parameters[i].IsOut)
                    {
                        il.Ldarg(1);
                        il.Ldc_I4(i);
                        il.Ldelem(paramInfoType);
                        il.Call(paramInfoGetValue);

                        if (parameters[i].ParameterType.GetElementType().IsValueType)
                        {
                            il.Unbox_Any(parameters[i].ParameterType.GetElementType());
                        }
                        else
                        {
                            il.Castclass(parameters[i].ParameterType.GetElementType());
                        }

                        il.Stloc(locals[parameters[i].Name]);
                    }
                }

                // Load target
                il.Ldarg(0);
                il.Ldfld(concrete);

                // Push call values onto stack
                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].IsOut || parameters[i].ParameterType.IsByRef)
                    {
                        il.Ldloca(locals[parameters[i].Name]);
                    }
                    else
                    {
                        il.Ldarg(1);
                        il.Ldc_I4(i);
                        il.Ldelem(paramInfoType);
                        il.Call(paramInfoGetValue);

                        if (parameters[i].ParameterType.IsValueType || parameters[i].ParameterType.IsGenericParameter)
                        {
                            il.Unbox_Any(parameters[i].ParameterType);
                        }
                        else
                        {
                            il.Castclass(parameters[i].ParameterType);
                        }
                    }
                }

                // Call intercepted method
                il.Call(methodToIntercept);

                var paramInfoSetValue = paramInfoType.GetProperty("Value").GetSetMethod();

                // Copy out/ref parameter values back into passed-in parameters array
                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].IsOut || parameters[i].ParameterType.IsByRef)
                    {
                        il.Ldarg(1);
                        il.Ldc_I4(i);
                        il.Ldelem(paramInfoType);
                        il.Ldloc(locals[parameters[i].Name]);

                        if (parameters[i].ParameterType.GetElementType().IsValueType)
                        {
                            il.Box(parameters[i].ParameterType.GetElementType());
                        }

                        il.Call(paramInfoSetValue);
                    }
                }

                il.Ret();

                LogIlCode(il);
            }

            return(method);
        }
예제 #14
0
        private static void DefineMethodOverrideWithInterception(TypeBuilder typeBuilder, MethodBuilder methodBuilder, MethodInfo overridedMethod, Dictionary <Type, FieldInfo> interceptorFields, MethodInfo genericInterceptionAction, MethodInfo voidInterceptionAction, FieldBuilder concreteInstance, ParameterInfo[] methodParams, Type[] genericParameterTypes, Type[] interceptors)
        {
            var @delegate = GenerateOverloadedMethodDelegate(overridedMethod, typeBuilder, concreteInstance);

            for (var i = 0; i < interceptors.Length; i++)
            {
                var interceptor = interceptors[i];

                @delegate = DefineMethodInterceptingDelegate(typeBuilder, overridedMethod, interceptorFields, genericInterceptionAction, voidInterceptionAction, genericParameterTypes, @delegate, i, interceptor);
            }

            using (var il = new GroboIL(methodBuilder))
            {
                var paramInfoType  = typeof(ParamInfo);
                var paramsInfoType = typeof(ParamInfo[]);
                var paramsInfo     = il.DeclareLocal(paramsInfoType);
                var paramInfo      = il.DeclareLocal(paramInfoType);

                il.Nop();

                il.Ldc_I4(methodParams.Length);
                il.Newarr(typeof(ParamInfo));
                il.Stloc(paramsInfo);

                var paramInfoConstructor = paramInfoType.GetConstructor(new[] { typeof(string), typeof(Type), typeof(bool), typeof(bool) });
                var paramInfoValueSetter = paramInfoType.GetProperty("Value").GetSetMethod();
                var getTypeMethod        = typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) });

                var idx = 0;
                foreach (var parameter in methodParams)
                {
                    // load array at index
                    il.Ldloc(paramsInfo);
                    il.Ldc_I4(idx++);

                    // Load ParamInfo.Name
                    il.Ldstr(parameter.Name);

                    // Load ParamInfo.Type
                    if (parameter.IsOut || parameter.ParameterType.IsByRef)
                    {
                        il.Ldtoken(parameter.ParameterType.GetElementType());
                    }
                    else
                    {
                        il.Ldtoken(parameter.ParameterType);
                    }

                    il.Call(getTypeMethod);

                    // Load ParamInfo.IsByRef
                    if (parameter.ParameterType.IsByRef)
                    {
                        il.Ldc_I4(1);
                    }
                    else
                    {
                        il.Ldc_I4(0);
                    }

                    // Load ParamInfo.IsOut
                    if (parameter.IsOut)
                    {
                        il.Ldc_I4(1);
                    }
                    else
                    {
                        il.Ldc_I4(0);
                    }

                    // instantiate ParamInfo
                    il.Newobj(paramInfoConstructor);
                    il.Stloc(paramInfo);

                    // Set ParamInfo.Value
                    il.Ldloc(paramInfo);
                    il.Ldarg(parameter.Position + 1);
                    if (parameter.IsOut || parameter.ParameterType.IsByRef)
                    {
                        il.Ldobj(parameter.ParameterType.GetElementType());

                        if (parameter.ParameterType.GetElementType().IsValueType || parameter.ParameterType.GetElementType().IsGenericParameter)
                        {
                            il.Box(parameter.ParameterType.GetElementType());
                        }
                    }
                    else
                    {
                        if (parameter.ParameterType.IsValueType || parameter.ParameterType.IsGenericParameter)
                        {
                            il.Box(parameter.ParameterType);
                        }
                    }

                    il.Call(paramInfoValueSetter);
                    il.Nop();

                    // push to array
                    il.Ldloc(paramInfo);
                    il.Stelem(paramInfoType);
                }

                il.Ldarg(0);
                il.Ldloc(paramsInfo);
                if (overridedMethod.IsGenericMethodDefinition)
                {
                    il.Call(@delegate.MakeGenericMethod(genericParameterTypes));
                }
                else
                {
                    il.Call(@delegate);
                }

                idx = 1;
                var paramInfoValueGetter = paramInfoType.GetProperty("Value").GetGetMethod();
                foreach (var parameter in methodParams)
                {
                    if (parameter.IsOut || parameter.ParameterType.IsByRef)
                    {
                        il.Ldarg(idx);
                        il.Ldloc(paramsInfo);
                        il.Ldc_I4(idx - 1);
                        il.Ldelem(paramInfoType);
                        il.Call(paramInfoValueGetter);

                        if (parameter.ParameterType.GetElementType().IsValueType)
                        {
                            il.Unbox_Any(parameter.ParameterType.GetElementType());
                        }

                        il.Stobj(parameter.ParameterType.GetElementType());
                    }

                    idx++;
                }

                il.Ret();

                LogIlCode(il);
            }
        }
예제 #15
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);
            var writableMember = member.TryGetWritableMemberInfo();

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [data]
                il.Ldarg(1); // stack: [data, ref index]
                switch (writableMember.MemberType)
                {
                case MemberTypes.Field:
                    var field = (FieldInfo)writableMember;
                    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)writableMember;
                    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)));
        }