private static Func <IntPtr, long, long> EmitRelJmpHooker() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(long), new[] { typeof(IntPtr), typeof(long) }, typeof(string), true); using (var il = new GroboIL(method)) { il.VerificationKind = TypesAssignabilityVerificationKind.LowLevelOnly; var cycleLabel = il.DefineLabel("cycle"); il.MarkLabel(cycleLabel); il.Ldarg(0); // stack: [ptr] il.Dup(); // stack: [ptr, ptr] var x = il.DeclareLocal(typeof(long)); il.Ldind(typeof(long)); // stack: [ptr, *ptr] il.Dup(); il.Stloc(x); // x = *ptr; stack: [ptr, newCode] il.Ldc_I8(unchecked ((long)0xFFFFFF0000000000)); il.And(); // stack: [ptr, x & 0xFFFFFF0000000000] il.Ldarg(1); // stack: [ptr, x & 0xFFFFFF0000000000, code] il.Or(); // stack: [ptr, (x & 0xFFFFFF0000000000) | code] il.Ldloc(x); // stack: [ptr, (x & 0xFFFFFF0000000000) | code, newCode] var methodInfo = typeof(Interlocked).GetMethod("CompareExchange", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(long).MakeByRefType(), typeof(long), typeof(long) }, null); il.Call(methodInfo); // stack: [Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode)] il.Ldloc(x); // stack: [Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode), newCode] il.Bne_Un(cycleLabel); // if(Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode) != newCode) goto cycle; stack: [] il.Ldloc(x); il.Ret(); } return((Func <IntPtr, long, long>)method.CreateDelegate(typeof(Func <IntPtr, long, long>))); }
protected override bool EmitInternal(MemberInitExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { ExpressionEmittersCollection.Emit(node.NewExpression, context, out resultType); // stack: [new obj(args)] GroboIL il = context.Il; if (!node.Type.IsValueType) { foreach (MemberAssignment assignment in node.Bindings) { il.Dup(); context.EmitLoadArguments(assignment.Expression); context.EmitMemberAssign(node.Type, assignment.Member); } } else { using (var temp = context.DeclareLocal(node.Type)) { il.Stloc(temp); il.Ldloca(temp); foreach (MemberAssignment assignment in node.Bindings) { il.Dup(); context.EmitLoadArguments(assignment.Expression); context.EmitMemberAssign(node.Type, assignment.Member); } // todo или il.Ldobj()? il.Pop(); il.Ldloc(temp); } } return(false); }
public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext) { var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] { Type, typeof(bool), typeof(WriterContext) }, sizeCounterBuilderContext.Module, true); sizeCounterBuilderContext.SetSizeCounterMethod(Type, method); using (var il = new GroboIL(method)) { var context = new SizeCounterMethodBuilderContext(sizeCounterBuilderContext, il); var notEmptyLabel = il.DefineLabel("notEmpty"); if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty { context.ReturnForNull(); // return for null } il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty if (!Type.IsValueType && IsReference && sizeCounterBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) { // Pack reference var index = il.DeclareLocal(typeof(int)); context.LoadContext(); // stack: [context] il.Dup(); // stack: [context, context] il.Ldfld(WriterContext.IndexField); // stack: [context, context.index] il.Stloc(index); // index = context.index; stack: [context] il.Ldfld(WriterContext.ObjectsField); // stack: [context.objects] context.LoadObj(); // stack: [context.objects, obj] il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.ContainsKey(null))); // stack: [context.object.ContainsKey(obj)] var storeLocationLabel = il.DefineLabel("storeLocation"); il.Brfalse(storeLocationLabel); // if(!context.objects.ContainsKey(obj)) goto storeLocation; stack: [] context.LoadContext(); // stack: [context] il.Dup(); // stack: [context, context] il.Ldfld(WriterContext.ReferencesField); // stack: [context, context.references] il.Ldc_I4(1); // stack: [context, context.references, 1] il.Add(); // stack: [context, context.references + 1] il.Stfld(WriterContext.ReferencesField); // context.references += 1; stack: [] il.Ldc_I4(5); // stack: [5] il.Ret(); // return 5 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); } CountSizeNotEmpty(context); // Count size il.Ret(); } var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate); }
private static TryParseDelegate EmitTryParseDelegate() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(string), typeof(DateTimeTypeCode), typeof(object).MakeByRefType() }, typeof(string), true); var xsdDateTimeType = typeof(XmlReader).Assembly.GetTypes().FirstOrDefault(type => type.Name == "XsdDateTime"); if (xsdDateTimeType == null) { throw new InvalidOperationException("The type 'XsdDateTime' is not found"); } var tryParseMethod = xsdDateTimeType.GetMethod("TryParse", BindingFlags.Static | BindingFlags.NonPublic); if (tryParseMethod == null) { throw new InvalidOperationException("The method 'XsdDateTime.TryParse' is not found"); } using (var il = new GroboIL(method)) { il.Ldarg(0); // stack: [value] il.Ldarg(1); // stack: [value, typeCode] var strongBoxType = typeof(StrongBox <>).MakeGenericType(xsdDateTimeType); var strongBox = il.DeclareLocal(strongBoxType); il.Ldarg(2); // stack: [value, typeCode, ref result] il.Newobj(strongBoxType.GetConstructor(Type.EmptyTypes)); // stack: [value, typeCode, ref result, new StrongBox<XsdDateTime>()] il.Dup(); il.Stloc(strongBox); // strongBox = new StrongBox<XsdDateTime>(); stack: [value, typeCode, ref result, strongBox] il.Stind(typeof(object)); // result = strongBox; stack: [value, typeCode] il.Ldloc(strongBox); // stack: [value, typeCode, strongBox] il.Ldflda(strongBoxType.GetField("Value", BindingFlags.Instance | BindingFlags.Public)); // stack: [value, typeCode, ref strongBox.Value] il.Call(tryParseMethod); // stack: [XsdDateTime.TryParse(value, typeCode, ref strongBox.Value] il.Ret(); } return((TryParseDelegate)method.CreateDelegate(typeof(TryParseDelegate))); }
private static Func <MethodBase, DynamicMethod> EmitTryCastToDynamicMethod() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(DynamicMethod), new[] { typeof(MethodBase) }, typeof(string), true); using (var il = new GroboIL(method)) { var RTDynamicMethod_t = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic); if (RTDynamicMethod_t == null) { throw new InvalidOperationException("Missing type 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod'"); } il.Ldarg(0); // stack: [method] il.Isinst(RTDynamicMethod_t); // stack: [method as RTDynamicMethod] il.Dup(); // stack: [method as RTDynamicMethod, method as RTDynamicMethod] var retLabel = il.DefineLabel("ret"); il.Brfalse(retLabel); // if(!(method is RTDynamicMethod)] goto ret; stack: [method as RTDynamicMethod] var m_owner_f = RTDynamicMethod_t.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic); if (m_owner_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod.m_owner'"); } il.Ldfld(m_owner_f); // stack: [((RTDynamicMethod)method).m_owner] il.MarkLabel(retLabel); il.Ret(); } return((Func <MethodBase, DynamicMethod>)method.CreateDelegate(typeof(Func <MethodBase, DynamicMethod>))); }
public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue) { BinaryStruct.WriteSizeChecker(il, buffer, offset, 2); var arr = il.DeclareLocal(typeof(byte[])); il.Ldloc(value); if (!listValue) { il.Call(prop.Getter); } il.Dup(); il.Pop(); il.Call(writeBitConverterMethodInfo); il.Stloc(arr); il.Ldloc(buffer); il.Ldloc(offset); il.Ldloc(arr); il.Ldc_I4(0); il.Ldelem(typeof(byte)); il.Stelem(typeof(byte)); for (int i = 1; i < 2; i++) { il.Ldloc(buffer); il.Ldloc(offset); il.Ldc_I4(i); il.Add(); il.Ldloc(arr); il.Ldc_I4(i); il.Ldelem(typeof(byte)); il.Stelem(typeof(byte)); } BinaryStruct.WriteOffsetAppend(il, offset, 2); }
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()); } }
private static void EmitXPlusPlus(this GroboIL il, GroboIL.Local intLocal) { il.Ldloc(intLocal); il.Dup(); il.Ldc_I4(1); il.Add(); il.Stloc(intLocal); }
private static void EmitMinusMinusX(this GroboIL il, GroboIL.Local intLocal) { il.Ldloc(intLocal); il.Ldc_I4(1); il.Sub(); il.Dup(); il.Stloc(intLocal); }
private static Func <object, object> EmitResolveVarArgsMethod() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true); using (var il = new GroboIL(method)) { var VarArgMethod_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.VarArgMethod"); if (VarArgMethod_t == null) { throw new InvalidOperationException("Missing type 'System.Reflection.Emit.VarArgMethod'"); } il.Ldarg(0); // stack: [value] il.Isinst(VarArgMethod_t); // stack: [(VarArgMethod)value] var retLabel = il.DefineLabel("ret"); il.Dup(); // stack: [(VarArgMethod)value, (VarArgMethod)value] il.Brfalse(retLabel); // if(!(value is VarArgMethod)) goto ret; stack: [value as VarArgMethod] var m_method_f = VarArgMethod_t.GetField("m_method", BindingFlags.Instance | BindingFlags.NonPublic); if (m_method_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_method'"); } var m_dynamicMethod_f = VarArgMethod_t.GetField("m_dynamicMethod", BindingFlags.Instance | BindingFlags.NonPublic); if (m_dynamicMethod_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_dynamicMethod'"); } var temp = il.DeclareLocal(VarArgMethod_t); il.Dup(); il.Stloc(temp); // temp = (VarArgMethod)value; stack: [(VarArgMethod)value] il.Ldfld(m_method_f); // stack: [((VarArgMethod)value).m_method] il.Dup(); // stack: [((VarArgMethod)value).m_method, ((VarArgMethod)value).m_method] il.Brtrue(retLabel); // if(((VarArgMethod)value).m_method != null) goto ret; stack: [((VarArgMethod)value).m_method] il.Pop(); // stack: [] il.Ldloc(temp); // stack: [(VarArgMethod)value] il.Ldfld(m_dynamicMethod_f); // stack: [((VarArgMethod)value).m_dynamicMethod] il.MarkLabel(retLabel); il.Ret(); } return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>))); }
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 static Func <object, object> EmitResolveGenericMethodInfo() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true); using (var il = new GroboIL(method)) { var GenericMethodInfo_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.GenericMethodInfo"); if (GenericMethodInfo_t == null) { throw new InvalidOperationException("Missing type 'System.Reflection.Emit.GenericMethodInfo'"); } il.Ldarg(0); // stack: [value] il.Isinst(GenericMethodInfo_t); // stack: [(GenericMethodInfo)value] var retLabel = il.DefineLabel("ret"); il.Dup(); // stack: [(GenericMethodInfo)value, (GenericMethodInfo)value] il.Brfalse(retLabel); // if(!(value is GenericMethodInfo)) goto ret; stack: [value as GenericMethodInfo] var m_methodHandle_f = GenericMethodInfo_t.GetField("m_methodHandle", BindingFlags.Instance | BindingFlags.NonPublic); if (m_methodHandle_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_methodHandle'"); } var m_context_f = GenericMethodInfo_t.GetField("m_context", BindingFlags.Instance | BindingFlags.NonPublic); if (m_context_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_context'"); } var temp = il.DeclareLocal(GenericMethodInfo_t); il.Dup(); il.Stloc(temp); // temp = (GenericMethodInfo)value; stack: [(GenericMethodInfo)value] il.Ldfld(m_methodHandle_f); // stack: [((GenericMethodInfo)value).m_methodHandle] il.Ldloc(temp); // stack: [((GenericMethodInfo)value).m_methodHandle, (GenericMethodInfo)value] il.Ldfld(m_context_f); // stack: [((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context] var getMethodFromHandle_m = HackHelpers.GetMethodDefinition <int>(x => MethodBase.GetMethodFromHandle(default(RuntimeMethodHandle), default(RuntimeTypeHandle))); il.Call(getMethodFromHandle_m); // stack: [MethodBase.GetMethodFromHandle(((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context)] il.MarkLabel(retLabel); il.Ret(); } return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>))); }
public void TestBrfalse() { 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.Brfalse(label); il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2())); il.MarkLabel(label); il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null))); il.Ret(); Console.WriteLine(il.GetILCode()); } }
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); }
private static void BuildChildren(TypeBuilder typeBuilder, int n, Context context) { var property = typeBuilder.DefineProperty("Children", PropertyAttributes.None, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes); var getter = typeBuilder.DefineMethod("get_Children", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes); using (var il = new GroboIL(getter)) { il.Ldc_I4(n); // stack: [n] il.Newarr(typeof(MethodCallNode)); // stack: [new int[n] -> values] for (int i = 0; i < n; ++i) { il.Dup(); // stack: [values, values] il.Ldc_I4(i); // stack: [values, values, i] il.Ldarg(0); // stack: [values, values, i, this] il.Ldfld(context.values[i]); // stack: [values, values, i, this.values_{i}] il.Stelem(typeof(MethodCallNode)); // values[i] = this.values_{i}; stack: [values] } il.Castclass(typeof(IEnumerable <MethodCallNode>)); il.Ret(); } property.SetGetMethod(getter); typeBuilder.DefineMethodOverride(getter, typeof(MethodCallNodeEdges).GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance).GetGetMethod()); }
public void TestEnumerable() { var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.RunAndSave); var module = assembly.DefineDynamicModule(Guid.NewGuid().ToString(), "test.cil", true); var symWriter = module.GetSymWriter(); var symbolDocumentWriter = symWriter.DefineDocument("test.cil", Guid.Empty, Guid.Empty, Guid.Empty); var typeBuilder = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public); var method = typeBuilder.DefineMethod("Qzz", MethodAttributes.Public); var genericParameters = method.DefineGenericParameters("TZzz"); var parameter = genericParameters[0]; method.SetParameters(typeof(List <>).MakeGenericType(parameter), typeof(Func <,>).MakeGenericType(parameter, typeof(int))); method.DefineParameter(2, ParameterAttributes.In, "list"); method.SetReturnType(typeof(int)); using (var il = new GroboIL(method, symbolDocumentWriter)) { il.Ldarg(1); il.Dup(); var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); il.Pop(); il.Ldc_I4(0); il.Newarr(parameter); il.MarkLabel(notNullLabel); var temp = il.DeclareLocal(typeof(IEnumerable <>).MakeGenericType(parameter), "arr"); il.Stloc(temp); il.Ldloc(temp); il.Ldarg(2); il.Call(HackHelpers.GetMethodDefinition <int[]>(ints => ints.Sum(x => x)).GetGenericMethodDefinition().MakeGenericMethod(parameter)); il.Ret(); Console.WriteLine(il.GetILCode()); } var type = typeBuilder.CreateType(); var instance = Activator.CreateInstance(type); type.GetMethod("Qzz", BindingFlags.Instance | BindingFlags.Public).MakeGenericMethod(typeof(int)).Invoke(instance, new object[] { null, null }); }
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>)); }
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 static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true); var indices = new List <int>(); using (var il = new GroboIL(method)) { var idx = il.DeclareLocal(typeof(int), "idx"); var retFalseLabel = il.DefineLabel("retFalse"); for (int i = 0; i < numberOfSegments; ++i) { var firstKeyInSegment = keys[i * numberOfKeysPerSegment]; var lastKeyInSegment = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment]; il.Ldarg(1); // stack: [key] il.Ldc_I4(firstKeyInSegment); // stack: [key, firstKey] var nextSegmentLabel = il.DefineLabel("nextSegment"); il.Blt(nextSegmentLabel, false); // if(key < firstKey) goto nextSegment; stack: [] il.Ldarg(1); // stack: [key] il.Ldc_I4(lastKeyInSegment); // stack: [key, lastKey] il.Bgt(nextSegmentLabel, false); // if(key > lastKey) goto nextSegment; stack: [] il.Ldarg(0); // stack: [closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.indices)); // stack: [closure.indices] il.Ldarg(1); // stack: [closure.indices, key] il.Ldc_I4(firstKeyInSegment - indices.Count); // stack: [closure.indices, key, diff] il.Sub(); // stack: [closure.indices, key - diff] il.Ldelem(typeof(int)); // stack: [closure.indices[key - diff]] il.Dup(); il.Stloc(idx); // idx = closure.indices[key - diff]; stack: [idx] il.Ldc_I4(0); // stack: [idx, 0] il.Blt(retFalseLabel, false); // if(idx < 0) goto retFalse; stack: [] il.Ldarg(2); // stack: [ref value] il.Ldarg(0); // stack: [ref value, closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.values)); // stack: [ref value, closure.values] il.Ldloc(idx); // stack: [ref value, closure.values, idx] il.Ldelem(typeof(T)); // stack: [ref value, closure.values[idx]] il.Stind(typeof(T)); // value = closure.values[idx]; stack: [] il.Ldc_I4(1); // stack: [true] il.Ret(); il.MarkLabel(nextSegmentLabel); var segmentLength = lastKeyInSegment - firstKeyInSegment + 1; int start = indices.Count; for (int j = 0; j < segmentLength; ++j) { indices.Add(-1); } for (int j = 0; j < numberOfKeysPerSegment; ++j) { indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j; } } il.MarkLabel(retFalseLabel); il.Ldarg(2); // stack: [ref value] if (typeof(T).IsValueType) { il.Initobj(typeof(T)); // value = default(T); stack: [] } else { il.Ldnull(); // stack: [ref value, null] il.Stind(typeof(T)); // value = null; stack: [] } il.Ldc_I4(0); // stack: [false] il.Ret(); } var closure = new Closure <T> { indices = indices.ToArray(), values = values }; return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure)); }
public bool EmitMemberAccess(MemberExpression node, GroboIL.Label returnDefaultValueLabel, bool checkNullReferences, bool extend, ResultType whatReturn, out Type resultType, out LocalHolder owner) { bool result = false; owner = null; Type type = node.Expression == null ? null : node.Expression.Type; Type ownerType; GroboIL il = Il; if (node.Expression == null) { ownerType = null; } else { result |= ExpressionEmittersCollection.Emit(node.Expression, this, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out type); // stack: [obj] if (!type.IsValueType) { ownerType = type; } else { ownerType = type.MakeByRefType(); using (var temp = DeclareLocal(type)) { il.Stloc(temp); il.Ldloca(temp); } } if (checkNullReferences && node.Expression != ParsedLambda.ClosureParameter && node.Expression != ParsedLambda.ConstantsParameter && !node.Expression.Type.IsStaticClosure()) { result |= EmitNullChecking(node.Expression.Type, returnDefaultValueLabel); } } extend &= CanAssign(node.Member); Type memberType = GetMemberType(node.Member); ConstructorInfo constructor = memberType.GetConstructor(Type.EmptyTypes); extend &= (memberType.IsClass && constructor != null) || memberType.IsArray; if (!extend) { EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member] } else { if (node.Expression == null) { EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member] var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull"); il.Dup(); il.Brtrue(memberIsNotNullLabel); il.Pop(); Create(memberType); using (var newobj = DeclareLocal(memberType)) { il.Stloc(newobj); il.Ldloc(newobj); EmitMemberAssign(type, node.Member); il.Ldloc(newobj); } MarkLabelAndSurroundWithSP(memberIsNotNullLabel); } else { owner = DeclareLocal(ownerType); il.Stloc(owner); il.Ldloc(owner); EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member] var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull"); il.Dup(); il.Brtrue(memberIsNotNullLabel); il.Pop(); il.Ldloc(owner); Create(memberType); using (var newobj = DeclareLocal(memberType)) { il.Stloc(newobj); il.Ldloc(newobj); EmitMemberAssign(type, node.Member); il.Ldloc(newobj); } MarkLabelAndSurroundWithSP(memberIsNotNullLabel); } } return(result); }
public static void OutputValue(GroboIL il, Type t) { il.Dup(); //il.Box(t); il.Call(typeof(BinaryStruct).GetMethod("OutputBuffer", BindingFlags.NonPublic | BindingFlags.Static)); }
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 GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue) { var exitLabel = il.DefineLabel("exit"); BinaryStruct.WriteSizeChecker(il, buffer, offset, 4); var arr = il.DeclareLocal(typeof(byte[])); il.Ldarg(1); il.Call(codingMethodInfo); il.Ldloc(value); if (!listValue) { il.Call(prop.Getter); } il.Dup(); BinaryStruct.WriteObjectNull(il, exitLabel, buffer, offset, typeSize); il.Call(currentStruct.Coding.GetType().GetMethod("GetBytes", new Type[] { typeof(string) })); il.Stloc(arr); if (prop.PropertyInfo != null) { il.Ldloc(value); il.Call(prop.TypeSizeProperty.Getter); il.Stloc(typeSize); } else { il.Ldc_I4(prop.TypeSize); il.Stloc(typeSize); } BinaryStruct.WriteSizeChecker(il, buffer, offset, typeSize); var ivar = il.DeclareLocal(typeof(int)); var point = il.DefineLabel("for_label"); il.Ldc_I4(0); il.Stloc(ivar); il.MarkLabel(point); //body il.Ldloc(buffer); il.Ldloc(ivar); il.Ldloc(offset); il.Add(); il.Ldloc(arr); il.Ldloc(ivar); il.Ldelem(typeof(byte)); il.Stelem(typeof(byte)); //end body il.Ldc_I4(1); il.Ldloc(ivar); il.Add(); il.Stloc(ivar); il.Ldloc(ivar); il.Ldloc(typeSize); il.Clt(false); il.Brtrue(point); BinaryStruct.WriteOffsetAppend(il, offset, typeSize); }
protected override bool EmitInternal(MethodCallExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var result = false; GroboIL il = context.Il; var method = node.Method; Expression obj; IEnumerable <Expression> arguments; IEnumerable <ParameterInfo> parameters; bool isStatic = method.IsStatic; if (!isStatic) { obj = node.Object; arguments = node.Arguments; parameters = method.GetParameters(); } else if (method.DeclaringType == typeof(Enumerable)) { obj = node.Arguments[0]; arguments = node.Arguments.Skip(1); parameters = method.GetParameters().Skip(1); } else { obj = null; arguments = node.Arguments; parameters = method.GetParameters(); } Type type = obj == null ? null : obj.Type; if (obj != null) { Type actualType; result |= ExpressionEmittersCollection.Emit(obj, context, returnDefaultValueLabel, isStatic ? ResultType.Value : ResultType.ByRefValueTypesOnly, extend, out actualType); // stack: [obj] if (actualType == typeof(void)) { throw new InvalidOperationException("Unable to call method on void"); } if (actualType.IsValueType && !isStatic) { using (var temp = context.DeclareLocal(actualType)) { il.Stloc(temp); il.Ldloca(temp); } actualType = actualType.MakeByRefType(); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences) && !actualType.IsValueType) { if (method.DeclaringType != typeof(Enumerable)) { result |= context.EmitNullChecking(type, returnDefaultValueLabel); } else { var arrIsNotNullLabel = il.DefineLabel("arrIsNotNull"); il.Dup(); il.Brtrue(arrIsNotNullLabel); il.Pop(); il.Ldc_I4(0); il.Newarr(GetElementType(type)); context.MarkLabelAndSurroundWithSP(arrIsNotNullLabel); } } } var parametersArray = parameters.ToArray(); var argumentsArray = arguments.ToArray(); for (int i = 0; i < argumentsArray.Length; i++) { var argument = argumentsArray[i]; var parameter = parametersArray[i]; if (parameter.ParameterType.IsByRef) { Type argumentType; var options = context.Options; context.Options = CompilerOptions.None; ExpressionEmittersCollection.Emit(argument, context, null, ResultType.ByRefAll, false, out argumentType); context.Options = options; if (!argumentType.IsByRef) { throw new InvalidOperationException("Expected type by reference"); } } else { Type argumentType; context.EmitLoadArgument(argument, true, out argumentType); } } il.Call(method, type); resultType = node.Type; return(result); }
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(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); }
private Func <object> BuildConstants(Type type, ClosureSubstituter closureSubstituter) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object[]) }, typeof(ExpressionClosureBuilder), true); var root = Expression.Parameter(type); var consts = new object[hashtable.Count]; using (var il = new GroboIL(method)) { il.Newobj(type.GetConstructor(Type.EmptyTypes)); // stack: [new Constants()] var result = il.DeclareLocal(type, "result"); il.Stloc(result); // result = new Constants(); stack: [] int index = 0; foreach (DictionaryEntry entry in hashtable) { var pair = (Tuple <Type, object>)entry.Key; var constType = pair.Item1; consts[index] = pair.Item2 is Expression?closureSubstituter.Visit((Expression)pair.Item2) : pair.Item2; var fieldAccessor = constantsBuilder.MakeAccess(root, ((int?)entry.Value).Value); var pathToField = new List <FieldInfo>(); while (fieldAccessor.NodeType != ExpressionType.Parameter) { var memberExpression = (MemberExpression)fieldAccessor; pathToField.Add((FieldInfo)memberExpression.Member); fieldAccessor = memberExpression.Expression; } pathToField.Reverse(); il.Ldloc(result); for (int i = 0; i < pathToField.Count - 1; ++i) { il.Ldflda(pathToField[i]); // stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] var fieldType = pathToField[i].FieldType; il.Ldind(fieldType); // stack: [ref result.field, result.field] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(result.field != null) goto notNull; stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] il.Newobj(fieldType.GetConstructor(Type.EmptyTypes)); // stack: [ref result.field, ref result.field, new field()] il.Stind(fieldType); // result.field = new field(); stack: [ref result.field] il.MarkLabel(notNullLabel); il.Ldind(fieldType); // stack: [result.field] } il.Ldarg(0); // stack: [path, args] il.Ldc_I4(index++); // stack: [path, args, index] il.Ldelem(typeof(object)); // stack: [path, args[index]] var field = pathToField.Last(); if (!constType.IsValueType) { il.Castclass(field.FieldType); // stack: [path, (FieldType)args[index]] } else { il.Unbox_Any(constType); if (field.FieldType != constType) { var constructor = field.FieldType.GetConstructor(new[] { constType }); if (constructor == null) { throw new InvalidOperationException(string.Format("Missing constructor of type '{0}' with parameter of type '{1}'", Formatter.Format(field.FieldType), Formatter.Format(constType))); } il.Newobj(constructor); } } il.Stfld(field); // path.field = (FieldType)args[index]; stack: [] } il.Ldloc(result); il.Ret(); } var func = (Func <object[], object>)method.CreateDelegate(typeof(Func <object[], object>)); return(() => func(consts)); }
public static bool Emit(Expression zarr, Expression zindex, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var arrayType = zarr.Type; var isArray = arrayType.IsArray; if (!isArray && !arrayType.IsList()) { throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'"); } var itemType = isArray ? arrayType.GetElementType() : arrayType.GetGenericArguments()[0]; GroboIL il = context.Il; EmittingContext.LocalHolder arrayIndex = null; bool extendArray = extend && (CanAssign(zarr) || !isArray); bool extendArrayElement = extend && itemType.IsClass; var result = false; if (!extendArray) { result |= ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.Value, extend, out arrayType); // stack: [array] if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { result = true; il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); // stack: [array, arrayIndex] if (context.Options.HasFlag(CompilerOptions.CheckArrayIndexes)) { result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] il.Ble(returnDefaultValueLabel, false); // if(array.Length <= arrayIndex) goto returnDefaultValue; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] } else if (extendArrayElement || !isArray) { arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] } } else { EmittingContext.LocalHolder arrayOwner = null; switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: Type type; ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.ByRefAll, true, out type); // stack: [ref array] arrayOwner = context.DeclareLocal(type); il.Dup(); // stack: [ref array, ref array] il.Stloc(arrayOwner); // arrayOwner = ref array; stack: [ref array] il.Ldind(zarr.Type); // stack: [array] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; Type memberType; context.EmitMemberAccess(memberExpression, returnDefaultValueLabel, context.Options.HasFlag(CompilerOptions.CheckNullReferences), true, ResultType.ByRefValueTypesOnly, out memberType, out arrayOwner); // stack: [array] break; default: throw new InvalidOperationException("Cannot extend array for expression with node type '" + zarr.NodeType + "'"); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] var bigEnoughLabel = il.DefineLabel("bigEnough"); il.Bgt(bigEnoughLabel, false); // if(array.Length > arrayIndex) goto bigEnough; stack: [array] using (var array = context.DeclareLocal(arrayType)) { il.Stloc(array); // stack: [] if (!isArray) { EnsureCount(context, array, arrayIndex, arrayType); } else { il.Ldloca(array); // stack: [ref array] il.Ldloc(arrayIndex); // stack: [ref array, arrayIndex] il.Ldc_I4(1); // stack: [ref array, arrayIndex, 1] il.Add(); // stack: [ref array, arrayIndex + 1] il.Call(arrayResizeMethod.MakeGenericMethod(arrayType.GetElementType())); // Array.Resize(ref array, 1 + arrayIndex); stack: [] switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: il.Ldloc(arrayOwner); // stack: [ref parameter] il.Ldloc(array); // stack: [ref parameter, array] il.Stind(arrayType); // parameter = array; stack: [] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; if (memberExpression.Expression != null) { il.Ldloc(arrayOwner); } il.Ldloc(array); switch (memberExpression.Member.MemberType) { case MemberTypes.Field: il.Stfld((FieldInfo)memberExpression.Member); break; case MemberTypes.Property: var propertyInfo = (PropertyInfo)memberExpression.Member; var setter = propertyInfo.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(propertyInfo.ReflectedType.ToString(), "set_" + propertyInfo.Name); } il.Call(setter, memberExpression.Expression == null ? null : memberExpression.Expression.Type); break; default: throw new NotSupportedException("Member type '" + memberExpression.Member.MemberType + "' is not supported"); } break; default: throw new InvalidOperationException("Unable to assign array to an expression with node type '" + zarr.NodeType); } } il.Ldloc(array); context.MarkLabelAndSurroundWithSP(bigEnoughLabel); } } if (!isArray) { // TODO: это злобно, лист при всех операциях меняет _version, а мы нет EmitLoadField(context, arrayType, arrayType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); arrayType = itemType.MakeArrayType(); } if (extendArrayElement) { // stack: [array] var constructor = itemType.GetConstructor(Type.EmptyTypes); if (itemType.IsArray || constructor != null) { using (var array = context.DeclareLocal(arrayType)) { il.Dup(); // stack: [array, array] il.Stloc(array); // stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldelem(itemType); // stack: [array[arrayIndex]] var elementIsNotNullLabel = il.DefineLabel("elementIsNotNull"); il.Brtrue(elementIsNotNullLabel); il.Ldloc(array); il.Ldloc(arrayIndex); context.Create(itemType); il.Stelem(itemType); context.MarkLabelAndSurroundWithSP(elementIsNotNullLabel); il.Ldloc(array); } } } if (arrayIndex != null) { il.Ldloc(arrayIndex); arrayIndex.Dispose(); } switch (whatReturn) { case ResultType.ByRefAll: il.Ldelema(itemType); resultType = itemType.MakeByRefType(); break; case ResultType.ByRefValueTypesOnly: if (itemType.IsValueType) { il.Ldelema(itemType); resultType = itemType.MakeByRefType(); } else { il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; } break; default: il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; break; } return(result); }
private static Type BuildMutatorsTreeCreator(int numberOfGenericParameters) { var typeBuilder = module.DefineType("MutatorsTreeCreator_" + numberOfGenericParameters, TypeAttributes.Public | TypeAttributes.Class); var genericParameters = typeBuilder.DefineGenericParameters(new[] { "TSource" }.Concat(new int[numberOfGenericParameters - 1].Select((i, index) => "T" + (index + 1))).ToArray()); var interfaceType = typeof(IMutatorsTreeCreator <>).MakeGenericType(genericParameters.Last()); var method = TypeBuilder.GetMethod(interfaceType, typeof(IMutatorsTreeCreator <>).GetMethod(getMutatorsTreeMethodName, BindingFlags.Public | BindingFlags.Instance)); var methodBuilder = typeBuilder.DefineMethod(getMutatorsTreeMethodName, MethodAttributes.Public | MethodAttributes.Virtual, typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters.Last()), new[] { typeof(IDataConfiguratorCollectionFactory), typeof(IConverterCollectionFactory), typeof(MutatorsContext[]), typeof(MutatorsContext[]) }); using (var il = new GroboIL(methodBuilder)) { il.Ldarg(1); // stack: [dataConfiguratorCollectionFactory] il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[0]), typeof(IDataConfiguratorCollectionFactory)); // stack: [dataConfiguratorCollectionFactory.Get<TSource> = collection] var sourceCollectionIsNullLabel = il.DefineLabel("sourceCollectionIsNull"); il.Dup(); // stack: [collection, collection] il.Brfalse(sourceCollectionIsNullLabel); // if(collection == null) goto sourceCollectionIsNull; stack: [collection] il.Ldarg(3); // stack: [collection, mutatorsContexts] il.Ldc_I4(0); // stack: [collection, mutatorsContexts, 0] il.Ldelem(typeof(MutatorsContext)); // stack: [collection, mutatorsContexts[0]] il.Ldc_I4(0); // stack: [collection, mutatorsContexts[0], 0] // todo ich: избавиться от константы var collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[0]); il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [collection.GetMutatorsTree(mutatorsContexts[0], 0)] il.MarkLabel(sourceCollectionIsNullLabel); var current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[0])); for (var i = 0; i < numberOfGenericParameters - 1; ++i) { // First: Migrate tree il.Stloc(current); il.Ldarg(2); // stack: [converterCollectionFactory] il.Call(getConverterCollectionMethod.MakeGenericMethod(genericParameters[i + 1], genericParameters[i]), typeof(IConverterCollectionFactory)); // stack: [converterCollectionFactory.Get<T_i, T_i+1> = converterCollection] il.Dup(); // stack: [converterCollection, converterCollection] il.Ldloc(current); // stack: [converterCollection, converterCollection, current] il.Ldarg(4); // stack: [converterCollection, converterCollection, current, converterContexts] il.Ldc_I4(i); // stack: [converterCollection, converterCollection, current, converterContexts, i] il.Ldelem(typeof(MutatorsContext)); // stack: [converterCollection, converterCollection, current, converterContexts[i]] // todo ich: избавиться от константы //il.Call(collectionType.GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])] collectionType = typeof(IConverterCollection <,>).MakeGenericType(genericParameters[i + 1], genericParameters[i]); il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])] current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[i + 1])); il.Stloc(current); // current = converterCollection.Migrate(current, converterContexts[i]); stack: [converterCollection] // Second: Merge with validations tree il.Ldarg(4); // stack: [converterCollection, converterContexts] il.Ldc_I4(i); // stack: [converterCollection, converterContexts, i] il.Ldelem(typeof(MutatorsContext)); // stack: [converterCollection, converterContexts[i]] il.Ldc_I4(numberOfGenericParameters + i); // stack: [converterCollection, converterContexts[i], n + i] // todo ich: избавиться от константы //il.Call(collectionType.GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree] il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree] il.Ldloc(current); // stack: [validationsTree, current] //var mutatorsTreeType = typeof(MutatorsTreeBase<>).MakeGenericType(genericParameters[i + 1]); //il.Call(mutatorsTreeType.GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance), mutatorsTreeType); // stack: [validationsTree.Merge(current)] //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current)] il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current)] // Third: Merge with current mutators tree il.Ldarg(1); // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory] il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[i + 1]), typeof(IDataConfiguratorCollectionFactory)); // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory.Get<T_i+1> = collection] var collectionIsNullLabel = il.DefineLabel("collectionIsNull"); il.Dup(); // stack: [validationsTree.Merge(current), collection, collection] il.Brfalse(collectionIsNullLabel); // if(collection == null) goto collectionIsNull; stack: [validationsTree.Merge(current), collection] il.Ldarg(3); // stack: [validationsTree.Merge(current), collection, mutatorsContexts] il.Ldc_I4(i + 1); // stack: [validationsTree.Merge(current), collection, mutatorsContexts, i + 1] il.Ldelem(typeof(MutatorsContext)); // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1]] il.Ldc_I4(i + 1); // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1], 0] // todo ich: избавиться от константы collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[i + 1]); il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [validationsTree.Merge(current), collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)] il.MarkLabel(collectionIsNullLabel); //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current] il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current] } il.Ret(); } typeBuilder.DefineMethodOverride(methodBuilder, method); typeBuilder.AddInterfaceImplementation(interfaceType); return(typeBuilder.CreateType()); }
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 })); }