public void TestDifferentPathsGeneric() { var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); var module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); var type = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public); var method = type.DefineMethod("Qzz", MethodAttributes.Public | MethodAttributes.Static); var genericParameters = method.DefineGenericParameters("TZzz"); var parameter = genericParameters[0]; method.SetParameters(typeof(bool), typeof(C1 <>).MakeGenericType(parameter), typeof(C2 <>).MakeGenericType(parameter)); method.SetReturnType(typeof(void)); using (var il = new GroboIL(method)) { il.Ldarg(0); var label1 = il.DefineLabel("L1"); il.Brfalse(label1); il.Ldarg(1); var label2 = il.DefineLabel("L2"); il.Br(label2); il.MarkLabel(label1); il.Ldarg(2); il.MarkLabel(label2); il.Dup(); il.Call(HackHelpers.GetMethodDefinition <I1 <int> >(x => F1(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter)); il.Call(HackHelpers.GetMethodDefinition <I2 <int> >(x => F2(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter)); il.Ret(); Console.Write(il.GetILCode()); } }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (node.Conversion != null) { throw new NotSupportedException("Coalesce with conversion is not supported"); } // note ich: баг решарпера // ReSharper disable HeuristicUnreachableCode var left = node.Left; var right = node.Right; GroboIL il = context.Il; GroboIL.Label valueIsNullLabel = il.DefineLabel("valueIsNull"); Type leftType; bool labelUsed = ExpressionEmittersCollection.Emit(left, context, valueIsNullLabel, out leftType); if (left.Type.IsValueType) { using (var temp = context.DeclareLocal(left.Type)) { il.Stloc(temp); il.Ldloca(temp); } } labelUsed |= context.EmitNullChecking(left.Type, valueIsNullLabel); if (left.Type.IsValueType) { if (!left.Type.IsNullable()) { throw new InvalidOperationException("Type '" + left.Type + "' cannot be null"); } if (node.Type != left.Type) { context.EmitValueAccess(left.Type); } else { il.Ldobj(left.Type); } } var valueIsNotNullLabel = il.DefineLabel("valueIsNotNull"); il.Br(valueIsNotNullLabel); if (labelUsed) { context.MarkLabelAndSurroundWithSP(valueIsNullLabel); il.Pop(); } Type rightType; var result = ExpressionEmittersCollection.Emit(right, context, returnDefaultValueLabel, out rightType); context.MarkLabelAndSurroundWithSP(valueIsNotNullLabel); resultType = node.Type; return(result); // ReSharper restore HeuristicUnreachableCode }
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 void TestDifferentStructs() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(int) }, typeof(Test)); var il = new GroboIL(method); var loc1 = il.DeclareLocal(typeof(int?)); var loc2 = il.DeclareLocal(typeof(Qxx?)); var label1 = il.DefineLabel("zzz"); il.Ldarg(0); il.Brfalse(label1); il.Ldloc(loc1); var label2 = il.DefineLabel("qxx"); il.Br(label2); il.MarkLabel(label1); il.Ldloc(loc2); Assert.Throws <InvalidOperationException>(() => il.MarkLabel(label2)); }
protected override bool EmitInternal(TypeBinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { bool result; GroboIL il = context.Il; if (!node.Expression.Type.IsAssignableFrom(node.TypeOperand)) { il.Ldc_I4(0); result = false; } else if (node.Expression.Type == node.TypeOperand && node.TypeOperand.IsValueType) { il.Ldc_I4(1); result = false; } else { Type operandType; result = ExpressionEmittersCollection.Emit(node.Expression, context, returnDefaultValueLabel, ResultType.Value, extend, out operandType); if (operandType.IsValueType) { using (var temp = context.DeclareLocal(operandType)) { il.Stloc(temp); il.Ldloca(temp); } } var returnFalseLabel = il.DefineLabel("returnFalse"); il.Dup(); il.Brfalse(returnFalseLabel); il.Call(typeof(object).GetMethod("GetType"), operandType); il.Ldtoken(node.TypeOperand); il.Call(typeof(Type).GetMethod("GetTypeFromHandle")); il.Ceq(); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Pop(); il.Ldc_I4(0); context.MarkLabelAndSurroundWithSP(doneLabel); } resultType = typeof(bool); return(result); }
public void TestZ2() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(A), new[] { typeof(bool), typeof(B), typeof(C) }, typeof(Test)); using (var il = new GroboIL(method)) { il.Ldarg(0); var label1 = il.DefineLabel("label"); il.Brfalse(label1); il.Ldarg(1); var label2 = il.DefineLabel("label"); il.Br(label2); il.MarkLabel(label1); il.Ldarg(2); il.MarkLabel(label2); il.Ret(); Console.Write(il.GetILCode()); } }
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 TestBrtrue() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(C2) }, typeof(string), true); using (var il = new GroboIL(method)) { il.Ldarg(0); il.Dup(); var label = il.DefineLabel("L"); il.Brtrue(label); var label2 = il.DefineLabel("L"); il.Br(label2); il.MarkLabel(label); il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2())); il.MarkLabel(label2); il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null))); il.Ret(); Console.WriteLine(il.GetILCode()); } }
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)); }
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 EmitLoadIndex(Expression index, EmittingContext context, Type arrayType) { GroboIL il = context.Il; GroboIL.Label indexIsNullLabel = context.CanReturn ? il.DefineLabel("indexIsNull") : null; Type indexType; bool labelUsed = ExpressionEmittersCollection.Emit(index, context, indexIsNullLabel, out indexType); // stack: [array, index] if (indexType != typeof(int)) { throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'"); } if (labelUsed && context.CanReturn) { var indexIsNotNullLabel = il.DefineLabel("indexIsNotNull"); il.Br(indexIsNotNullLabel); context.MarkLabelAndSurroundWithSP(indexIsNullLabel); il.Pop(); il.Ldc_I4(0); context.MarkLabelAndSurroundWithSP(indexIsNotNullLabel); } }
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>))); }
public void TestDifferentPaths() { Console.WriteLine(Formatter.Format(typeof(Dictionary <string, int>).GetProperty("Values", BindingFlags.Public | BindingFlags.Instance).GetGetMethod())); var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(bool), typeof(C1), typeof(C2) }, typeof(string), true); using (var il = new GroboIL(method)) { il.Ldarg(0); var label1 = il.DefineLabel("L1"); il.Brfalse(label1); il.Ldarg(1); var label2 = il.DefineLabel("L2"); il.Br(label2); il.MarkLabel(label1); il.Ldarg(2); il.MarkLabel(label2); il.Dup(); il.Call(HackHelpers.GetMethodDefinition <I1>(x => F1(x))); il.Call(HackHelpers.GetMethodDefinition <I2>(x => F2(x))); il.Ret(); Console.Write(il.GetILCode()); } var action = method.CreateDelegate(typeof(Action <bool, C1, C2>)); }
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(" "); }
protected override bool EmitInternal(SwitchExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { GroboIL il = context.Il; var defaultLabel = il.DefineLabel("default"); var caseLabels = new GroboIL.Label[node.Cases.Count]; GroboIL.Label switchValueIsNullLabel = null; for (int index = 0; index < node.Cases.Count; index++) { caseLabels[index] = il.DefineLabel("case#" + index); } context.EmitLoadArguments(node.SwitchValue); using (var switchValue = context.DeclareLocal(node.SwitchValue.Type)) { il.Stloc(switchValue); Tuple <int, int, int> switchCase; if (context.ParsedLambda.ParsedSwitches.TryGetValue(node, out switchCase)) { // use simplified hashtable to locate the proper case var labels = new List <GroboIL.Label>(); for (int index = 0; index < node.Cases.Count; index++) { foreach (var testValue in node.Cases[index].TestValues) { if (((ConstantExpression)testValue).Value != null) { labels.Add(caseLabels[index]); } else { switchValueIsNullLabel = caseLabels[index]; } } } if (switchValueIsNullLabel != null) { if (!node.SwitchValue.Type.IsNullable()) { il.Ldloc(switchValue); } else { il.Ldloca(switchValue); context.EmitHasValueAccess(node.SwitchValue.Type); } il.Brfalse(switchValueIsNullLabel); } EmittingContext.LocalHolder pureSwitchValue = switchValue; if (node.SwitchValue.Type.IsNullable()) { pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]); il.Ldloca(switchValue); context.EmitValueAccess(node.SwitchValue.Type); il.Stloc(pureSwitchValue); } Type temp; ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item1), context, out temp); var type = node.SwitchValue.Type.IsNullable() ? node.SwitchValue.Type.GetGenericArguments()[0] : node.SwitchValue.Type; var typeCode = Type.GetTypeCode(type); switch (typeCode) { case TypeCode.Byte: case TypeCode.Char: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: il.Ldloc(pureSwitchValue); break; default: if (type.IsValueType) { il.Ldloca(pureSwitchValue); } else { il.Ldloc(pureSwitchValue); } il.Call(typeof(object).GetMethod("GetHashCode"), type); break; } using (var index = context.DeclareLocal(typeof(int))) { if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64) { il.Ldc_I8(switchCase.Item3); } else { il.Ldc_I4(switchCase.Item3); } il.Rem(true); if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64) { il.Conv <int>(); } il.Stloc(index); il.Ldloc(index); il.Ldelem(type); il.Ldloc(pureSwitchValue); if (node.Comparison != null) { il.Call(node.Comparison); } else { il.Ceq(); } il.Brfalse(defaultLabel); ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item2), context, out temp); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(labels.ToArray()); } if (pureSwitchValue != switchValue) { pureSwitchValue.Dispose(); } } else { // use a number of if/else branches to locate the proper case EmittingContext.LocalHolder pureSwitchValue = switchValue; EmittingContext.LocalHolder switchValueIsNull = null; if (node.SwitchValue.Type.IsNullable()) { pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]); switchValueIsNull = context.DeclareLocal(typeof(bool)); il.Ldloca(switchValue); il.Dup(); context.EmitValueAccess(node.SwitchValue.Type); il.Stloc(pureSwitchValue); context.EmitHasValueAccess(node.SwitchValue.Type); il.Stloc(switchValueIsNull); } for (int index = 0; index < node.Cases.Count; index++) { var caSe = node.Cases[index]; var label = caseLabels[index]; foreach (var testValue in caSe.TestValues) { context.EmitLoadArguments(testValue); GroboIL.Label elseLabel = null; if (testValue.Type.IsNullable()) { elseLabel = il.DefineLabel("else"); using (var temp = context.DeclareLocal(testValue.Type)) { il.Stloc(temp); il.Ldloca(temp); context.EmitHasValueAccess(testValue.Type); if (switchValueIsNull != null) { il.Ldloc(switchValueIsNull); il.Or(); il.Brfalse(label); il.Ldloca(temp); context.EmitHasValueAccess(testValue.Type); il.Ldloc(switchValueIsNull); il.And(); } il.Brfalse(elseLabel); il.Ldloca(temp); context.EmitValueAccess(testValue.Type); } } il.Ldloc(pureSwitchValue); if (node.Comparison != null) { il.Call(node.Comparison); } else { il.Ceq(); } il.Brtrue(label); if (elseLabel != null) { context.MarkLabelAndSurroundWithSP(elseLabel); } } } } } context.MarkLabelAndSurroundWithSP(defaultLabel); var doneLabel = il.DefineLabel("done"); context.EmitLoadArguments(node.DefaultBody); il.Br(doneLabel); for (int index = 0; index < node.Cases.Count; ++index) { context.MarkLabelAndSurroundWithSP(caseLabels[index]); context.EmitLoadArguments(node.Cases[index].Body); if (index < node.Cases.Count - 1) { il.Br(doneLabel); } } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = node.Type; return(false); }
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)); }
protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { GroboIL il = context.Il; var result = false; var operand = node.Operand; Type assigneeType; AssigneeKind assigneeKind; bool checkNullReferences = context.Options.HasFlag(CompilerOptions.CheckNullReferences); extend |= context.Options.HasFlag(CompilerOptions.ExtendOnAssign); GroboIL.Label assigneeIsNullLabel = null; bool assigneeIsNullLabelUsed = false; switch (operand.NodeType) { case ExpressionType.Parameter: assigneeType = null; assigneeKind = AssigneeKind.Parameter; checkNullReferences = false; break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)operand; if (memberExpression.Expression == null) { assigneeType = null; assigneeKind = memberExpression.Member is FieldInfo ? AssigneeKind.StaticField : AssigneeKind.StaticProperty; checkNullReferences = false; } else { bool closureAssign = memberExpression.Expression == context.ParsedLambda.ClosureParameter || memberExpression.Expression.Type.IsStaticClosure(); checkNullReferences &= !closureAssign; if (node.NodeType != ExpressionType.Assign && context.CanReturn) { result |= ExpressionEmittersCollection.Emit(memberExpression.Expression, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType); } else { assigneeIsNullLabel = !closureAssign && context.CanReturn ? il.DefineLabel("assigneeIsNull") : null; assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(memberExpression.Expression, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType); } assigneeKind = memberExpression.Member is FieldInfo ? AssigneeKind.InstanceField : AssigneeKind.InstanceProperty; } break; case ExpressionType.Index: var indexExpression = (IndexExpression)operand; if (indexExpression.Object == null) { throw new InvalidOperationException("Indexing of null object is invalid"); } if (indexExpression.Object.Type.IsArray && indexExpression.Object.Type.GetArrayRank() == 1) { if (node.NodeType != ExpressionType.Assign && context.CanReturn) { result |= ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, returnDefaultValueLabel, ResultType.ByRefAll, extend, out assigneeType); checkNullReferences = false; } else { assigneeIsNullLabel = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null; assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, assigneeIsNullLabel, ResultType.ByRefAll, extend, out assigneeType); } assigneeKind = AssigneeKind.SimpleArray; } else { if (node.NodeType != ExpressionType.Assign && context.CanReturn) { result |= ExpressionEmittersCollection.Emit(indexExpression.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType); } else { assigneeIsNullLabel = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null; assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(indexExpression.Object, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType); } assigneeKind = indexExpression.Indexer != null ? AssigneeKind.IndexedProperty : AssigneeKind.MultiDimensionalArray; } break; default: throw new InvalidOperationException("Unable to assign to an expression of type '" + operand.NodeType + "'"); } if (assigneeType != null && assigneeType.IsValueType) { using (var temp = context.DeclareLocal(assigneeType)) { il.Stloc(temp); il.Ldloca(temp); } assigneeType = assigneeType.MakeByRefType(); } if (assigneeIsNullLabelUsed) { context.EmitReturnDefaultValue(assigneeType, assigneeIsNullLabel, il.DefineLabel("assigneeIsNotNull")); } if (checkNullReferences) { il.Dup(); il.Brfalse(returnDefaultValueLabel); result = true; } if (assigneeType != null) { il.Dup(); } object[] arguments = EmitAccess(assigneeKind, operand, context); if (!operand.Type.IsNullable()) { if (whatReturn == ResultType.Void) { EmitOp(node.NodeType, node.Method, node.Type, context); EmitAssign(assigneeKind, operand, context, arguments); } else { if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign) { using (var assignmentResult = context.DeclareLocal(operand.Type)) { il.Stloc(assignmentResult); il.Ldloc(assignmentResult); EmitOp(node.NodeType, node.Method, node.Type, context); EmitAssign(assigneeKind, operand, context, arguments); il.Ldloc(assignmentResult); } } else { EmitOp(node.NodeType, node.Method, node.Type, context); using (var assignmentResult = context.DeclareLocal(operand.Type)) { il.Stloc(assignmentResult); EmitAssign(assigneeKind, operand, context, arguments, assignmentResult); il.Ldloc(assignmentResult); } } } } else { using (var value = context.DeclareLocal(operand.Type)) { il.Stloc(value); il.Ldloca(value); context.EmitHasValueAccess(operand.Type); var returnNullLabel = il.DefineLabel("returnNull"); il.Brfalse(returnNullLabel); il.Ldloca(value); context.EmitValueAccess(operand.Type); Type argumentType = operand.Type.GetGenericArguments()[0]; ConstructorInfo constructor = operand.Type.GetConstructor(new[] { argumentType }); if (whatReturn == ResultType.Void) { EmitOp(node.NodeType, node.Method, argumentType, context); il.Newobj(constructor); EmitAssign(assigneeKind, operand, context, arguments); } else { if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign) { EmitOp(node.NodeType, node.Method, argumentType, context); il.Newobj(constructor); EmitAssign(assigneeKind, operand, context, arguments); il.Ldloc(value); } else { EmitOp(node.NodeType, node.Method, argumentType, context); il.Newobj(constructor); using (var assignmentResult = context.DeclareLocal(operand.Type)) { il.Stloc(assignmentResult); EmitAssign(assigneeKind, operand, context, arguments, assignmentResult); il.Ldloc(assignmentResult); } } } var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnNullLabel); if (assigneeType != null) { il.Pop(); } if (whatReturn != ResultType.Void) { il.Ldloc(value); } context.MarkLabelAndSurroundWithSP(doneLabel); } } resultType = whatReturn == ResultType.Void ? typeof(void) : operand.Type; return(result); }
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 = new Type[] { typeof(int), typeof(int) }; 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) }); // 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.Br(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 Action <Hashtable, Array, int> EmitCopyValues() { /* * private void CopyValues(Hashtable hashtable, Array array, int arrayLength) * { * bucket[] buckets = hashtable.buckets; * int length = buckets.Length; * int arrayIndex = 0; * while (--length >= 0) * { * object key = buckets[length].key; * if ((key != null) && (key != hashtable.buckets)) * { * if (arrayIndex >= arrayLength) * return; * array.SetValue(buckets[length].val, arrayIndex++); * } * } * } */ var dynamicMethod = new DynamicMethod( Guid.NewGuid().ToString(), typeof(void), new[] { typeof(Hashtable), typeof(Array), typeof(int) }, typeof(Hashtable), true); var bucketsFieldInfo = typeof(Hashtable).GetField("buckets", BindingFlags.Instance | BindingFlags.NonPublic); var bucketType = typeof(Hashtable).GetNestedType("bucket", BindingFlags.NonPublic); var bucketArrayType = bucketType.MakeArrayType(); var keyFieldInfo = bucketType.GetField("key", BindingFlags.Instance | BindingFlags.Public); var valFieldInfo = bucketType.GetField("val", BindingFlags.Instance | BindingFlags.Public); var setValueMethodInfo = typeof(Array).GetMethod("SetValue", new[] { typeof(object), typeof(int) }); using (var il = new GroboIL(dynamicMethod)) { var buckets = il.DeclareLocal(bucketArrayType, "buckets"); var length = il.DeclareLocal(typeof(int), "length"); var arrayIndex = il.DeclareLocal(typeof(int), "arrayIndex"); var key = il.DeclareLocal(typeof(object), "key"); var cycleStartLabel = il.DefineLabel("cycleStart"); var cycleNextLabel = il.DefineLabel("cycleNext"); var endLabel = il.DefineLabel("end"); il.EmitSetIntToZero(arrayIndex); il.Ldarg(0); // stack: hashtable il.Ldfld(bucketsFieldInfo); // stack: hashtable::buckets il.Stloc(buckets); il.Ldloc(buckets); // stack: hashtable::buckets il.Ldlen(); // stack: buckets.length il.Conv <int>(); // stack: buckets.length (i4) il.Stloc(length); il.Br(cycleNextLabel); // jump(cycleNext) il.MarkLabel(cycleStartLabel); il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: *bucket[current] il.Ldfld(keyFieldInfo); // stack: key il.Stloc(key); // 2: key il.Ldloc(key); // stack: key il.Brfalse(cycleNextLabel); // jump(cycleNext) if key == null il.Ldloc(key); // stack: key il.Ldarg(0); // stack+: hashtable il.Ldfld(bucketsFieldInfo); // stack: key, hashtable::buckets il.Beq(cycleNextLabel); // jump(cycleNext) if key == hashtable::buckets (какой-то хитрый хак hashtable-а) il.Ldloc(arrayIndex); // stack: arrayIndex il.Ldarg(2); // stack+: arrayLength il.Bge(endLabel, false); // jump(end) if arrayIndex >= arrayLength il.Ldarg(1); // stack: array (arg1) il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: array (arg1), *bucket[current] il.Ldfld(valFieldInfo); // stack: array (arg1), bucket[current].val il.EmitXPlusPlus(arrayIndex); // stack: array (arg1), bucket[current].val, arrayIndex++ il.Call(setValueMethodInfo); // array.SetValue(bucket[current].val, old_arrayIndex); il.MarkLabel(cycleNextLabel); il.EmitMinusMinusX(length); // stack: --current il.Ldc_I4(0); // stack+: 0 il.Bge(cycleStartLabel, false); // jump(cycleStart) if --current >= 0 il.MarkLabel(endLabel); il.Ret(); } return((Action <Hashtable, Array, int>)dynamicMethod.CreateDelegate(typeof(Action <Hashtable, Array, int>))); }
public void Test1() { Type overflow = typeof(OverflowException); ConstructorInfo exCtorInfo = overflow.GetConstructor( new[] { typeof(string) }); MethodInfo exToStrMI = overflow.GetMethod("ToString"); MethodInfo 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.Br(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()); } }
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 })); }
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 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)); }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { Expression left = node.Left; Expression right = node.Right; Type leftType, rightType; context.EmitLoadArgument(left, false, out leftType); context.EmitLoadArgument(right, false, out rightType); GroboIL il = context.Il; if (!leftType.IsNullable() && !rightType.IsNullable()) { if (node.Method != null) { il.Call(node.Method); } else { if (leftType.IsStruct() || rightType.IsStruct()) { throw new InvalidOperationException("Cannot compare structs"); } il.Ceq(); if (node.NodeType == ExpressionType.NotEqual) { il.Ldc_I4(1); il.Xor(); } } } else { var type = leftType; if (type != rightType) { throw new InvalidOperationException("Cannot compare objects of different types '" + leftType + "' and '" + rightType + "'"); } using (var localLeft = context.DeclareLocal(type)) using (var localRight = context.DeclareLocal(type)) { il.Stloc(localRight); il.Stloc(localLeft); if (node.Method != null) { il.Ldloca(localLeft); // stack: [&left] context.EmitHasValueAccess(type); // stack: [left.HasValue] il.Dup(); // stack: [left.HasValue, left.HasValue] il.Ldloca(localRight); // stack: [left.HasValue, left.HasValue, &right] context.EmitHasValueAccess(type); // stack: [left.HasValue, left.HasValue, right.HasValue] var notEqualLabel = il.DefineLabel("notEqual"); il.Bne_Un(notEqualLabel); // stack: [left.HasValue] var equalLabel = il.DefineLabel("equal"); il.Brfalse(equalLabel); il.Ldloca(localLeft); context.EmitValueAccess(type); il.Ldloca(localRight); context.EmitValueAccess(type); il.Call(node.Method); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(notEqualLabel); il.Pop(); il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 0 : 1); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(equalLabel); il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 1 : 0); context.MarkLabelAndSurroundWithSP(doneLabel); } else { il.Ldloca(localLeft); context.EmitValueAccess(type); il.Ldloca(localRight); context.EmitValueAccess(type); var notEqualLabel = il.DefineLabel("notEqual"); il.Bne_Un(notEqualLabel); il.Ldloca(localLeft); context.EmitHasValueAccess(type); il.Ldloca(localRight); context.EmitHasValueAccess(type); il.Ceq(); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(notEqualLabel); il.Ldc_I4(0); context.MarkLabelAndSurroundWithSP(doneLabel); if (node.NodeType == ExpressionType.NotEqual) { il.Ldc_I4(1); il.Xor(); } } } } resultType = typeof(bool); return(false); }
protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { Type operandType; var result = ExpressionEmittersCollection.Emit(node.Operand, context, returnDefaultValueLabel, ResultType.Value, extend, out operandType); GroboIL il = context.Il; if (node.NodeType == ExpressionType.IsTrue || node.NodeType == ExpressionType.IsFalse) { if (!operandType.IsNullable()) { if (node.Method != null) { il.Call(node.Method); } else if (operandType == typeof(bool)) { if (node.NodeType == ExpressionType.IsFalse) { il.Ldc_I4(1); il.Xor(); } } else { throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a type '" + operandType + "'"); } } else { using (var temp = context.DeclareLocal(operandType)) { il.Stloc(temp); il.Ldloca(temp); context.EmitHasValueAccess(operandType); var returnFalseLabel = il.DefineLabel("returnFalse"); il.Brfalse(returnFalseLabel); il.Ldloca(temp); context.EmitValueAccess(operandType); if (node.Method != null) { il.Call(node.Method); } else if (operandType == typeof(bool?)) { if (node.NodeType == ExpressionType.IsFalse) { il.Ldc_I4(1); il.Xor(); } } else { throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a type '" + operandType + "'"); } var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Ldc_I4(0); context.MarkLabelAndSurroundWithSP(doneLabel); } } } else { if (!operandType.IsNullable()) { if (node.Method != null) { il.Call(node.Method); } else { if (operandType.IsStruct()) { throw new InvalidOperationException("Cannot perform operation '" + node.NodeType + "' to a struct '" + operandType + "'"); } switch (node.NodeType) { case ExpressionType.UnaryPlus: break; case ExpressionType.Negate: il.Neg(); break; case ExpressionType.NegateChecked: using (var temp = context.DeclareLocal(operandType)) { il.Stloc(temp); il.Ldc_I4(0); context.EmitConvert(typeof(int), operandType); il.Ldloc(temp); il.Sub_Ovf(operandType.Unsigned()); } break; case ExpressionType.Increment: il.Ldc_I4(1); context.EmitConvert(typeof(int), operandType); il.Add(); break; case ExpressionType.Decrement: il.Ldc_I4(1); context.EmitConvert(typeof(int), operandType); il.Sub(); break; case ExpressionType.OnesComplement: il.Not(); break; default: throw new InvalidOperationException("Node type '" + node.NodeType + "' invalid at this point"); } } } else { using (var temp = context.DeclareLocal(operandType)) { il.Stloc(temp); il.Ldloca(temp); context.EmitHasValueAccess(operandType); var returnNullLabel = il.DefineLabel("returnLabel"); il.Brfalse(returnNullLabel); Type argumentType = operandType.GetGenericArguments()[0]; if (node.Method != null) { il.Ldloca(temp); context.EmitValueAccess(operandType); il.Call(node.Method); } else { switch (node.NodeType) { case ExpressionType.UnaryPlus: il.Ldloca(temp); context.EmitValueAccess(operandType); break; case ExpressionType.Negate: il.Ldloca(temp); context.EmitValueAccess(operandType); il.Neg(); break; case ExpressionType.NegateChecked: il.Ldc_I4(0); context.EmitConvert(typeof(int), argumentType); il.Ldloca(temp); context.EmitValueAccess(operandType); il.Sub_Ovf(argumentType.Unsigned()); break; case ExpressionType.Increment: il.Ldloca(temp); context.EmitValueAccess(operandType); il.Ldc_I4(1); context.EmitConvert(typeof(int), argumentType); il.Add(); break; case ExpressionType.Decrement: il.Ldloca(temp); context.EmitValueAccess(operandType); il.Ldc_I4(1); context.EmitConvert(typeof(int), argumentType); il.Sub(); break; case ExpressionType.OnesComplement: il.Ldloca(temp); context.EmitValueAccess(operandType); il.Not(); break; default: throw new InvalidOperationException("Node type '" + node.NodeType + "' invalid at this point"); } } il.Newobj(operandType.GetConstructor(new[] { argumentType })); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnNullLabel); context.EmitLoadDefaultValue(operandType); context.MarkLabelAndSurroundWithSP(doneLabel); } } } resultType = node.Type; return(result); }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { GroboIL il = context.Il; if (node.Method != null) { throw new NotSupportedException("Custom operator '" + node.NodeType + "' is not supported"); } Expression left = node.Left; Expression right = node.Right; Type leftType; context.EmitLoadArgument(left, false, out leftType); // stack: [left] if (leftType == typeof(bool)) { switch (node.NodeType) { case ExpressionType.AndAlso: { var returnFalseLabel = il.DefineLabel("returnFalse"); il.Brfalse(returnFalseLabel); // if(left == false) return false; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); // goto done; stack: [right] context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Ldc_I4(0); // stack: [false] if (rightType == typeof(bool?)) { il.Newobj(nullableBoolConstructor); // stack: [new bool?(false)] } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = rightType; break; } case ExpressionType.OrElse: { var returnTrueLabel = il.DefineLabel("returnTrue"); il.Brtrue(returnTrueLabel); // if(left == true) return true; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); // goto done; stack: [right] context.MarkLabelAndSurroundWithSP(returnTrueLabel); il.Ldc_I4(1); // stack: [true] if (rightType == typeof(bool?)) { il.Newobj(nullableBoolConstructor); // stack: [new bool?(true)] } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = rightType; break; } default: throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported"); } } else // bool? { switch (node.NodeType) { case ExpressionType.AndAlso: { /* * +-------+-------+-------+-------+ * | && | null | false | true | * +-------+-------+-------+-------+ * | null | null | false | null | * +-------+-------+-------+-------+ * | false | false | false | false | * +-------+-------+-------+-------+ * | true | null | false | true | * +-------+-------+-------+-------+ */ using (var localLeft = context.DeclareLocal(typeof(bool?))) { il.Stloc(localLeft); // localLeft = left; stack: [] il.Ldloca(localLeft); // stack: [&localLeft] context.EmitHasValueAccess(typeof(bool?)); // stack: [localLeft.HasValue] il.Ldc_I4(1); // stack: [localLeft.HasValue, true] il.Xor(); // stack: [!localLeft.HasValue] il.Ldloca(localLeft); // stack: [!localLeft.HasValue, &localLeft] context.EmitValueAccess(typeof(bool?)); // stack: [!localLeft.HasValue, localLeft.Value] il.Or(); // stack: [!localLeft.HasValue || localLeft.Value] var returnFalseLabel = il.DefineLabel("returnFalse"); il.Brfalse(returnFalseLabel); // if(localLeft == false) goto returnFalse; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] using (var localRight = context.DeclareLocal(rightType)) { il.Stloc(localRight); // localRight = right; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldc_I4(1); // stack: [localRight.HasValue, true] il.Xor(); // stack: [!localRight.HasValue] il.Ldloca(localRight); // stack: [!localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [!localRight.HasValue, localRight.Value] il.Or(); // stack: [!localRight.HasValue || localRight.Value] } il.Brfalse(returnFalseLabel); // if(localRight == false) goto returnFalse; if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldloca(localRight); // stack: [localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [localRight.HasValue, localRight.Value] il.And(); // stack: [localRight.HasValue && localRight.Value] } var returnLeftLabel = il.DefineLabel("returnLeft"); il.Brtrue(returnLeftLabel); // if(localRight == true) goto returnLeft; il.Ldloca(localLeft); // stack: [&localLeft] il.Initobj(typeof(bool?)); // localLeft = default(bool?); stack: [] context.MarkLabelAndSurroundWithSP(returnLeftLabel); il.Ldloc(localLeft); // stack: [localLeft] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Ldc_I4(0); // stack: [false] il.Newobj(nullableBoolConstructor); // new bool?(false) context.MarkLabelAndSurroundWithSP(doneLabel); resultType = typeof(bool?); } } break; } case ExpressionType.OrElse: { /* * +-------+-------+-------+-------+ * | || | null | false | true | * +-------+-------+-------+-------+ * | null | null | null | true | * +-------+-------+-------+-------+ * | false | null | false | true | * +-------+-------+-------+-------+ * | true | true | true | true | * +-------+-------+-------+-------+ */ using (var localLeft = context.DeclareLocal(typeof(bool?))) { il.Stloc(localLeft); // localLeft = left; stack: [] il.Ldloca(localLeft); // stack: [&localLeft] context.EmitHasValueAccess(typeof(bool?)); // stack: [localLeft.HasValue] il.Ldloca(localLeft); // stack: [localLeft.HasValue, &localLeft] context.EmitValueAccess(typeof(bool?)); // stack: [localLeft.HasValue, localLeft.Value] il.And(); // stack: [localLeft.HasValue && localLeft.Value] var returnTrueLabel = il.DefineLabel("returnTrue"); il.Brtrue(returnTrueLabel); // if(localLeft == true) goto returnTrue; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] using (var localRight = context.DeclareLocal(rightType)) { il.Stloc(localRight); // localRight = right; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldloca(localRight); // stack: [localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [localRight.HasValue, localRight.Value] il.And(); // stack: [localRight.HasValue && localRight.Value] } il.Brtrue(returnTrueLabel); // if(localRight == true) goto returnTrue; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldc_I4(1); // stack: [localRight.HasValue, true] il.Xor(); // stack: [!localRight.HasValue] il.Ldloca(localRight); // stack: [!localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [!localRight.HasValue, localRight.Value] il.Or(); // stack: [!localRight.HasValue || localRight.Value] } var returnLeftLabel = il.DefineLabel("returnLeft"); il.Brfalse(returnLeftLabel); // if(localRight == false) goto returnLeft; il.Ldloca(localLeft); // stack: [&localLeft] il.Initobj(typeof(bool?)); // localLeft = default(bool?); stack: [] context.MarkLabelAndSurroundWithSP(returnLeftLabel); il.Ldloc(localLeft); // stack: [localLeft] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnTrueLabel); il.Ldc_I4(1); // stack: [true] il.Newobj(nullableBoolConstructor); // new bool?(true) context.MarkLabelAndSurroundWithSP(doneLabel); resultType = typeof(bool?); } } break; } default: throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported"); } } return(false); }