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); }
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); }
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); }
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); }
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 })); }
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); }
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); }
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)); }
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(" "); }
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(" "); }
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)); }
/// <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()); }
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); }
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); } }
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))); }