public static Func <Dictionary <string, object>, object> GenerateMethod(Type type) { var da = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName("dyn"), // call it whatever you want AssemblyBuilderAccess.RunAndSave); var dm = da.DefineDynamicModule("dyn_mod", "dyn.dll"); var dt = dm.DefineType("dyn_type"); var emiter = Emit <Func <int> > .NewDynamicMethod("MyMethod"); var method = dt.DefineMethod( "Foo", MethodAttributes.Public | MethodAttributes.Static, typeof(object), new[] { typeof(Dictionary <string, object>) }); method.DefineParameter(1, ParameterAttributes.None, "dictionary"); using (var il = new GroboIL(method)) { var target = il.DeclareLocal(type); var value = il.DeclareLocal(typeof(object)); il.Newobj(type.GetConstructor(Type.EmptyTypes)); // [Person] il.Stloc(target); // [] foreach (var property in type.GetProperties()) { var label = il.DefineLabel("ifLabel"); il.Ldarg(0); // [Dictionary<String, Object>] il.Ldstr(property.Name); // [Dictionary<String, Object>, String] il.Ldloca(value); // [Dictionary<String, Object>, String, Object&] il.Call(typeof(Dictionary <string, object>) .GetMethod("TryGetValue")); // [Boolean] il.Brfalse(label); // [] il.Ldloc(target); // [Person] il.Ldloc(value); // [Person, Object] il.Castclass(typeof(string)); // [Dictionary<String, Object>, String] il.Call(property.GetSetMethod(true)); // [] il.MarkLabel(label); } il.Ldloc(target); il.Ret(); Console.WriteLine(il.GetILCode()); } dt.CreateType(); da.Save("dyn.dll"); return((dic) => dt.GetMethod("Foo").Invoke(null, new object[] { dic })); }
private void LoadTupleField(GroboIL il, ValueTupleField tupleFiled) { il.Ldstr(tupleFiled.NameInUserCode); il.Ldarga(0); il.Ldfld(tupleFiled.FieldInfo); if (tupleFiled.FieldInfo.FieldType.IsValueType) { il.Box(tupleFiled.FieldInfo.FieldType); } }
private Func <string, string> BuildSwitch4() { Init(new[] { "0", "2", "5", "1000001", "7", "1000000" }); var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(string) }, Module, true); using (var il = new GroboIL(dynamicMethod)) { var zzzLabel = il.DefineLabel("zzz"); var qxxLabel = il.DefineLabel("qxx"); var qzzLabel = il.DefineLabel("qzz"); var xxxLabel = il.DefineLabel("xxx"); var index = il.DeclareLocal(typeof(uint)); il.Ldfld(typeof(TestPerformance).GetField("testValues2")); il.Ldarg(0); il.Call(typeof(object).GetMethod("GetHashCode"), typeof(string)); il.Ldc_I4(testValues2.Length); il.Rem(true); il.Stloc(index); il.Ldloc(index); il.Ldelem(typeof(string)); il.Ldarg(0); il.Call(typeof(object).GetMethod("Equals", new[] { typeof(object) }), typeof(string)); il.Brfalse(xxxLabel); il.Ldfld(typeof(TestPerformance).GetField("indexes2")); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(zzzLabel, zzzLabel, qxxLabel, qxxLabel, qzzLabel, qzzLabel); il.Br(xxxLabel); il.MarkLabel(zzzLabel); il.Ldstr("zzz"); il.Ret(); il.MarkLabel(qxxLabel); il.Ldstr("qxx"); il.Ret(); il.MarkLabel(qzzLabel); il.Ldstr("qzz"); il.Ret(); il.MarkLabel(xxxLabel); il.Ldstr("xxx"); il.Ret(); } return((Func <string, string>)dynamicMethod.CreateDelegate(typeof(Func <string, string>))); }
public void TestHelloWorld() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(string), Type.EmptyTypes, typeof(Test)); using (var il = new GroboIL(method)) { il.Ldstr("Hello World"); il.Ret(); Console.Write(il.GetILCode()); } }
private Func <int, string> BuildSwitch2() { var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(int) }, Module, true); using (var il = new GroboIL(dynamicMethod)) { var zzzLabel = il.DefineLabel("zzz"); var qxxLabel = il.DefineLabel("qxx"); var qzzLabel = il.DefineLabel("qzz"); var xxxLabel = il.DefineLabel("xxx"); var index = il.DeclareLocal(typeof(uint)); il.Ldfld(typeof(TestPerformance).GetField("testValues")); il.Ldarg(0); il.Ldc_I4(14); il.Rem(true); il.Stloc(index); il.Ldloc(index); il.Ldelem(typeof(int)); il.Ldarg(0); il.Bne_Un(xxxLabel); il.Ldfld(typeof(TestPerformance).GetField("indexes")); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(zzzLabel, zzzLabel, qxxLabel, qzzLabel, qzzLabel, qxxLabel); il.Br(xxxLabel); il.MarkLabel(zzzLabel); il.Ldstr("zzz"); il.Ret(); il.MarkLabel(qxxLabel); il.Ldstr("qxx"); il.Ret(); il.MarkLabel(qzzLabel); il.Ldstr("qzz"); il.Ret(); il.MarkLabel(xxxLabel); il.Ldstr("xxx"); il.Ret(); } return((Func <int, string>)dynamicMethod.CreateDelegate(typeof(Func <int, string>))); }
private static void EmitCrashIfValueIsNull(GroboIL il) { var box = il.DefineLabel("box"); il.Dup(); il.Brtrue(box); var crashConstructor = typeof(ArgumentException).GetConstructor(new[] { typeof(string) }); il.Ldstr("bad parameter"); il.Newobj(crashConstructor); il.Throw(); il.MarkLabel(box); }
private Func <int, string> BuildSwitch1() { var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(int) }, Module, true); using (var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); var zzzLabel = il.DefineLabel("zzz"); var qxxLabel = il.DefineLabel("qxx"); var qzzLabel = il.DefineLabel("qzz"); var xxxLabel = il.DefineLabel("xxx"); il.Switch(zzzLabel, xxxLabel, zzzLabel); il.Ldarg(0); il.Ldc_I4(5); il.Sub(); il.Switch(qxxLabel, xxxLabel, qzzLabel); il.Ldarg(0); il.Ldc_I4(0xf4240); il.Sub(); il.Switch(qzzLabel, qxxLabel); il.Br(xxxLabel); il.MarkLabel(zzzLabel); il.Ldstr("zzz"); il.Ret(); il.MarkLabel(qxxLabel); il.Ldstr("qxx"); il.Ret(); il.MarkLabel(qzzLabel); il.Ldstr("qzz"); il.Ret(); il.MarkLabel(xxxLabel); il.Ldstr("xxx"); il.Ret(); } return((Func <int, string>)dynamicMethod.CreateDelegate(typeof(Func <int, string>))); }
private IQxx BuildIfs(ModuleBuilder module, string[] keys) { var numberOfCases = keys.Length; var typeBuilder = module.DefineType("Ifs" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); typeBuilder.AddInterfaceImplementation(typeof(IQxx)); var fields = new FieldInfo[numberOfCases]; for (var i = 0; i < numberOfCases; ++i) { fields[i] = typeBuilder.DefineField(keys[i], typeof(int), FieldAttributes.Public); } var method = typeBuilder.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { typeof(string), typeof(int) }); method.DefineParameter(1, ParameterAttributes.In, "key"); method.DefineParameter(2, ParameterAttributes.In, "value"); using (var il = new GroboIL(method)) { var doneLabel = il.DefineLabel("done"); for (var i = 0; i < numberOfCases; ++i) { il.Ldarg(1); // stack: [key] il.Ldstr(keys[i]); // stack: [key, keys[i]] il.Call(stringEqualityOperator); // stack: [key == keys[i]] var nextKeyLabel = il.DefineLabel("nextKey"); il.Brfalse(nextKeyLabel); // if(key != keys[i]) goto nextKey; stack: [] il.Ldarg(0); il.Ldarg(2); il.Stfld(fields[i]); il.Br(doneLabel); il.MarkLabel(nextKeyLabel); } il.MarkLabel(doneLabel); il.Ret(); } typeBuilder.DefineMethodOverride(method, typeof(IQxx).GetMethod("Set")); var type = typeBuilder.CreateType(); return((IQxx)Activator.CreateInstance(type)); }
public void TestFarsh() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int) }, typeof(Test)); using (var il = new GroboIL(method)) { var temp = il.DeclareLocal(typeof(int)); il.Ldarg(0); // stack: [x] var label0 = il.DefineLabel("L"); il.Br(label0); // goto L_0; stack: [x] il.Ldstr("zzz"); il.Ldobj(typeof(DateTime)); il.Mul(); il.Initobj(typeof(int)); var label1 = il.DefineLabel("L"); il.MarkLabel(label1); // stack: [x, 2] il.Stloc(temp); // temp = 2; stack: [x] var label2 = il.DefineLabel("L"); il.MarkLabel(label2); // stack: [cur] il.Ldarg(0); // stack: [cur, x] il.Mul(); // stack: [cur * x = cur] il.Ldloc(temp); // stack: [cur, temp] il.Ldc_I4(1); // stack: [cur, temp, 1] il.Sub(); // stack: [cur, temp - 1] il.Stloc(temp); // temp = temp - 1; stack: [cur] il.Ldloc(temp); // stack: [cur, temp] il.Ldc_I4(0); // stack: [cur, temp, 0] il.Bgt(label2, false); // if(temp > 0) goto L_2; stack: [cur] var label3 = il.DefineLabel("L"); il.Br(label3); // goto L_3; stack: [cur] il.MarkLabel(label0); // stack: [x] il.Ldc_I4(2); // stack: [x, 2] il.Br(label1); // goto L_1; stack: [x, 2] il.MarkLabel(label3); // stack: [cur] il.Ret(); // return cur; stack: [] Console.Write(il.GetILCode()); } }
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)); }
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); } }
public void Test1() { var overflow = typeof(OverflowException); var exCtorInfo = overflow.GetConstructor(new[] { typeof(string) }); var exToStrMI = overflow.GetMethod("ToString"); var writeLineMI = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int), typeof(int) }, typeof(TestTryCatch)); using (var il = new GroboIL(method)) { GroboIL.Local tmp1 = il.DeclareLocal(typeof(int)); GroboIL.Local tmp2 = il.DeclareLocal(overflow); // In order to successfully branch, we need to create labels // representing the offset IL instruction block to branch to. // These labels, when the MarkLabel(Label) method is invoked, // will specify the IL instruction to branch to. // GroboIL.Label failed = il.DefineLabel("failed"); GroboIL.Label endOfMthd = il.DefineLabel("end"); // Begin the try block. il.BeginExceptionBlock(); // First, load argument 0 and the integer value of "100" onto the // stack. If arg0 > 100, branch to the label "failed", which is marked // as the address of the block that throws an exception. // il.Ldarg(0); il.Ldc_I4(100); il.Bgt(failed, false); // Now, check to see if argument 1 was greater than 100. If it was, // branch to "failed." Otherwise, fall through and perform the addition, // branching unconditionally to the instruction at the label "endOfMthd". // il.Ldarg(1); il.Ldc_I4(100); il.Bgt(failed, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); // Store the result of the addition. il.Stloc(tmp1); il.Leave(endOfMthd); // If one of the arguments was greater than 100, we need to throw an // exception. We'll use "OverflowException" with a customized message. // First, we load our message onto the stack, and then create a new // exception object using the constructor overload that accepts a // string message. // il.MarkLabel(failed); il.Ldstr("Cannot accept values over 100 for add."); il.Newobj(exCtorInfo); // We're going to need to refer to that exception object later, so let's // store it in a temporary variable. Since the store function pops the // the value/reference off the stack, and we'll need it to throw the // exception, we will subsequently load it back onto the stack as well. il.Stloc(tmp2); il.Ldloc(tmp2); // Throw the exception now on the stack. il.Throw(); // Start the catch block for OverflowException. // il.BeginCatchBlock(overflow); // When we enter the catch block, the thrown exception // is on the stack. Store it, then load the format string // for WriteLine. // il.Stloc(tmp2); il.Ldstr("Caught {0}"); // Push the thrown exception back on the stack, then // call its ToString() method. Note that if this catch block // were for a more general exception type, like Exception, // it would be necessary to use the ToString for that type. // il.Ldloc(tmp2); il.Call(exToStrMI); // The format string and the return value from ToString() are // now on the stack. Call WriteLine(string, object). // il.Call(writeLineMI); // Since our function has to return an integer value, we'll load -1 onto // the stack to indicate an error, and store it in local variable tmp1. // il.Ldc_I4(-1); il.Stloc(tmp1); // End the exception handling block. il.EndExceptionBlock(); // The end of the method. If no exception was thrown, the correct value // will be saved in tmp1. If an exception was thrown, tmp1 will be equal // to -1. Either way, we'll load the value of tmp1 onto the stack and return. // il.MarkLabel(endOfMthd); il.Ldloc(tmp1); il.Ret(); Console.WriteLine(il.GetILCode()); } }
public void Test2() { AssemblyName myAssemblyName = new AssemblyName(); myAssemblyName.Name = "AdderExceptionAsm"; // Create dynamic assembly. AppDomain myAppDomain = Thread.GetDomain(); AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.RunAndSave); // Create a dynamic module. ModuleBuilder myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true); var symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty); TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder"); Type[] adderParams = { typeof(int), typeof(int) }; ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor(new[] { typeof(string) }); MethodInfo myExToStrMI = typeof(OverflowException).GetMethod("ToString"); MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); // Define method to add two numbers. MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public | MethodAttributes.Static, typeof(int), adderParams); using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter)) { // Declare local variable. GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int)); GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException)); // Define label. GroboIL.Label myFailedLabel = il.DefineLabel("failed"); GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end"); // Begin exception block. il.BeginExceptionBlock(); il.Ldarg(0); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(1); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); il.Stloc(myLocalBuilder1); il.Leave(myEndOfMethodLabel); il.MarkLabel(myFailedLabel); il.Ldstr("Cannot accept values over 10 for add."); il.Newobj(myConstructorInfo); il.Stloc(myLocalBuilder2); il.Ldloc(myLocalBuilder2); // Throw the exception. il.Throw(); // Call 'BeginExceptFilterBlock'. il.BeginExceptFilterBlock(); il.WriteLine("Except filter block called."); // Call catch block. il.BeginCatchBlock(null); // Call other catch block. il.BeginCatchBlock(typeof(OverflowException)); il.Ldstr("{0}"); il.Ldloc(myLocalBuilder2); il.Call(myExToStrMI); il.Call(myWriteLineMI); il.Ldc_I4(-1); il.Stloc(myLocalBuilder1); // Call finally block. il.BeginFinallyBlock(); il.WriteLine("Finally block called."); // End the exception block. il.EndExceptionBlock(); il.MarkLabel(myEndOfMethodLabel); il.Ldloc(myLocalBuilder1); il.Ret(); Console.WriteLine(il.GetILCode()); } }
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); }
private Type BuildReaderInvoker() { var argument = Type.GetGenericArguments()[0]; var typeBuilder = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class); var reader = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private); var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private); var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(IntPtr), typeof(long) }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); // stack: [this] il.Ldarg(1); // stack: [this, reader] il.Stfld(reader); // this.reader = reader; stack: [] il.Ldarg(0); // stack: [this] il.Ldarg(2); // stack: [this, serializerId] il.Stfld(serializerId); // this.serializerId = serializerId; stack: [] il.Ret(); } var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] { typeof(byte[]) }); using (var il = new GroboIL(method)) { var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true); il.Ldarg(1); // stack: [data] il.Ldc_I4(0); // stack: [data, 0] il.Ldelema(typeof(byte)); // stack: [&data[0]] il.Stloc(pinnedData); // pinnedData = &data[0]; stack: [] var index = il.DeclareLocal(typeof(int), "index"); il.Ldc_I4(0); // stack: [0] il.Stloc(index); // index = 0; stack: [] var context = il.DeclareLocal(typeof(ReaderContext), "context"); il.Ldarg(0); // stack: [this] il.Ldfld(serializerId); // stack: [this.serializerId] il.Ldarg(1); // stack: [this.serializerId, data] il.Ldlen(); // stack: [this.serializerId, data.Length] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0, 0] il.Newobj(typeof(ReaderContext).GetConstructor(new[] { typeof(long), typeof(int), typeof(int), typeof(int) })); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)] il.Stloc(context); // context = new ReaderContext(..); stack: [] var result = il.DeclareLocal(argument, "result"); il.Ldloc(pinnedData); // stack: [data] il.Conv <IntPtr>(); // stack: [(IntPtr)data] il.Ldloca(index); // stack: [(IntPtr)data, ref index] il.Ldloca(result); // stack: [(IntPtr)data, ref index, ref result] il.Ldloc(context); // stack: [(IntPtr)data, ref index, ref result, context] il.Ldarg(0); // stack: [(IntPtr)data, ref index, ref result, context, this] il.Ldfld(reader); // stack: [(IntPtr)data, ref index, ref result, context, this.reader] var parameterTypes = new[] { typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: [] il.FreePinnedLocal(pinnedData); // pinnedData = null; stack: [] var retLabel = il.DefineLabel("ret"); il.Ldarg(1); // stack: [data] il.Ldlen(); // stack: [data.Length] il.Ldloc(index); // stack: [data.Length, index] il.Beq(retLabel); // if(data.Length == index) goto ret; stack: [] il.Ldstr("Encountered extra data"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(retLabel); il.Ldloc(result); il.Ret(); } return(typeBuilder.CreateType()); }
public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext) { var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) }, readerTypeBuilderContext.Module, true); readerTypeBuilderContext.SetReaderMethod(Type, method); using (var il = new GroboIL(method)) { var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference); ReadTypeCodeAndCheck(context); // Read TypeCode and check if (!Type.IsValueType && IsReference) { // Read reference context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var notReadLabel = il.DefineLabel("notRead"); il.Brfalse(notReadLabel); context.LoadIndex(); // stack: [external index] context.LoadContext(); // stack: [external index, context] il.Ldfld(ReaderContext.StartField); // stack: [external index, context.start] il.Sub(); // stack: [external index - context.start] il.Stloc(context.Index); // index = external index - context.start; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(context.Index); // stack: [context.objects, index] var obj = il.DeclareLocal(typeof(object)); il.Ldloca(obj); object dummy; il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)] il.Brfalse(notReadLabel); // if(!context.objects.TryGetValue(index, out obj)) goto notRead; context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] context.IncreaseIndexBy1(); // Skip type code context.SkipValue(); // Skip value - it has already been read il.Ret(); il.MarkLabel(notReadLabel); il.Ldloc(context.TypeCode); // stack: [typeCode] il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference] var readUsualLabel = il.DefineLabel("readUsual"); il.Bne_Un(readUsualLabel); // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull"); il.Brtrue(objectsIsNotNullLabel); // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects] il.Ldstr("Reference is not valid at this point"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(objectsIsNotNullLabel); context.IncreaseIndexBy1(); // index = index + 1; stack: [] il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); var reference = il.DeclareLocal(typeof(int)); il.Ldind(typeof(int)); // stack: [*(int*)data[index]] il.Stloc(reference); // reference = *(int*)data[index]; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(context.Index); // stack: [index] il.Ldloc(reference); // stack: [index, reference] var goodReferenceLabel = il.DefineLabel("goodReference"); il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: [] il.Ldstr("Bad reference"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(goodReferenceLabel); context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(reference); // stack: [context.objects, reference] il.Ldloca(obj); // stack: [context.objects, reference, ref obj] il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)] var readObjectLabel = il.DefineLabel("readObject"); il.Brfalse(readObjectLabel); // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: [] context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] il.Ret(); il.MarkLabel(readObjectLabel); // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted context.LoadData(); // stack: [data] il.Ldloc(reference); // stack: [data, reference] context.LoadContext(); // stack: [data, reference, context] il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start] il.Add(); // stack: [data, reference + context.start] il.Stloc(reference); // reference += context.start; stack: [data] il.Ldloca(reference); // stack: [data, ref reference] context.LoadResultByRef(); // stack: [data, ref reference, ref result] context.LoadContext(); // stack: [data, ref reference, ref result, context] context.CallReader(Type); il.Ret(); il.MarkLabel(readUsualLabel); } ReadNotEmpty(context); // Read obj il.Ret(); } var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate); }
private static void EmitValue(GroboIL il, object value) { //value.GetType() is the "real" type, only all pointers are UIntPtr and nullables are BoxedNullable //It can be: //Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Enum, IntPtr, UIntPtr //Or their nullable equivalents //Or string switch (value) { case bool boolean: il.Ldc_I4(boolean ? 1 : 0); break; case char character: il.Ldc_I4(character); break; case sbyte int8: il.Ldc_I4(int8); break; case byte uint8: il.Ldc_I4(uint8); break; case short int16: il.Ldc_I4(int16); break; case ushort uint16: il.Ldc_I4(uint16); break; case int int32: il.Ldc_I4(int32); break; case uint uint32: il.Ldc_I4((int)uint32); break; case long int64: il.Ldc_I8(int64); break; case ulong uint64: il.Ldc_I8((long)uint64); break; case float float32: il.Ldc_R4(float32); break; case double float64: il.Ldc_R8(float64); break; case decimal decimal128: il.LdDec(decimal128); break; case DateTime dateTime: var local = il.DeclareLocal(typeof(DateTime)); il.Ldloca(local); il.Ldc_I8(dateTime.Ticks); il.Ldc_I4((int)dateTime.Kind); il.Call(typeof(DateTime).GetConstructor(new[] { typeof(long), typeof(DateTimeKind) })); il.Ldloc(local); break; case UIntPtr unint: il.Ldc_IntPtr(Unsafe.As <UIntPtr, IntPtr>(ref unint)); break; case IntPtr nint: il.Ldc_IntPtr(nint); break; case Enum enumeration: var underlyingType = Enum.GetUnderlyingType(enumeration.GetType()); var underlyingValue = Convert.ChangeType(enumeration, underlyingType); EmitValue(il, underlyingValue); break; case BoxedNullable boxedNullable: EmitValue(il, boxedNullable.UnderlyingValue); il.Newobj(boxedNullable.NullableType.GetConstructor(new[] { boxedNullable.UnderlyingType })); break; case string str: il.Ldstr(str); break; default: throw new ArgumentException($"Value {value} of type {value.GetType()} is not supported by the emitter."); } }
public void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext) { var method = new DynamicMethod("Write_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { Type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }, writerTypeBuilderContext.Module, true); writerTypeBuilderContext.SetWriterMethod(Type, method); using (var il = new GroboIL(method)) { var context = new WriterMethodBuilderContext(writerTypeBuilderContext, il); var notEmptyLabel = il.DefineLabel("notEmpty"); if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty { context.WriteNull(); // Write null & return } il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty if (!Type.IsValueType && IsReference && writerTypeBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) { // Pack reference var index = il.DeclareLocal(typeof(int)); context.LoadIndex(); // stack: [external index] context.LoadContext(); // stack: [external index, context] il.Ldfld(WriterContext.StartField); // stack: [external index, context.start] il.Sub(); // stack: [external index - context.start] il.Stloc(index); // index = external index - context.start; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] context.LoadObj(); // stack: [context.objects, obj] var reference = il.DeclareLocal(typeof(int)); il.Ldloca(reference); // stack: [context.objects, obj, ref reference] int dummy; il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.TryGetValue(null, out dummy))); // stack: [context.object.TryGetValue(obj, out reference)] var storeLocationLabel = il.DefineLabel("storeLocation"); il.Brfalse(storeLocationLabel); // Current object is in dict il.Ldloc(index); il.Ldloc(reference); // stack: [index, reference] var skipSelfLabel = il.DefineLabel("skipSelf"); il.Beq(skipSelfLabel); // if(index == reference) goto skipSelf; stack: [] il.Ldloc(index); // stack: [index] il.Ldloc(reference); // stack: [index, reference] var badReferenceLabel = il.DefineLabel("badReference"); il.Blt(badReferenceLabel, false); // if(index < reference) goto badReference; stack: [] context.WriteTypeCode(GroBufTypeCode.Reference); // result[index++] = GroBufTypeCode.Reference context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(reference); // stack: [&result[index], reference] il.Stind(typeof(int)); // *(int *)&result[index] = reference context.IncreaseIndexBy4(); // index += 4 il.Ret(); il.MarkLabel(badReferenceLabel); il.Ldstr("Bad reference"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(storeLocationLabel); context.LoadContext(); // stack: [context] il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] context.LoadObj(); // stack: [context.objects, obj] il.Ldloc(index); // stack: [context.objects, obj, index] il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); il.MarkLabel(skipSelfLabel); } WriteNotEmpty(context); // Write obj il.Ret(); } var @delegate = method.CreateDelegate(typeof(WriterDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); writerTypeBuilderContext.SetWriterPointer(Type, pointer, @delegate); }
public void Test3() { // Create an assembly. AssemblyName myAssemblyName = new AssemblyName(); myAssemblyName.Name = "AdderExceptionAsm"; // Create dynamic assembly. AppDomain myAppDomain = Thread.GetDomain(); AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run); // Create a dynamic module. ModuleBuilder myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true); var symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty); TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder"); Type[] myAdderParams = new Type[] { typeof(int), typeof(int) }; // Create constructor. ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor( new Type[] { typeof(string) }); MethodInfo myExToStrMI = typeof(OverflowException).GetMethod("ToString"); MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) }); // Method to add two numbers. MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public | MethodAttributes.Static, typeof(int), myAdderParams); using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter)) { // Declare local variable. GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int)); GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException)); // Define label. GroboIL.Label myFailedLabel = il.DefineLabel("failed"); GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end"); // Begin exception block. il.BeginExceptionBlock(); il.Ldarg(0); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(1); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); il.Stloc(myLocalBuilder1); il.Br(myEndOfMethodLabel); il.MarkLabel(myFailedLabel); il.Ldstr("Cannot accept values over 10 for addition."); il.Newobj(myConstructorInfo); il.Stloc(myLocalBuilder2); il.Ldloc(myLocalBuilder2); // Call fault block. il.BeginFaultBlock(); //Throw exception. il.Newobj(typeof(NotSupportedException).GetConstructor(Type.EmptyTypes)); il.Throw(); // Call finally block. il.BeginFinallyBlock(); il.Ldstr("{0}"); il.Ldloc(myLocalBuilder2); il.Call(myExToStrMI); il.Call(myWriteLineMI); il.Ldc_I4(-1); il.Stloc(myLocalBuilder1); // End exception block. il.EndExceptionBlock(); il.MarkLabel(myEndOfMethodLabel); il.Ldloc(myLocalBuilder1); il.Ret(); Console.WriteLine(il.GetILCode()); } Type adderType = myTypeBuilder.CreateType(); object addIns = Activator.CreateInstance(adderType); object[] addParams = new object[2]; addParams[0] = 20; addParams[1] = 10; Console.WriteLine("{0} + {1} = {2}", addParams[0], addParams[1], adderType.InvokeMember("DoAdd", BindingFlags.InvokeMethod, null, addIns, addParams)); }