private void LoadValue(BitsValue value) { Generator.Ldc_I8((long)value.Number); Generator.Conv <ulong>(); Generator.Ldc_I4(value.Length); NumberToBitsValue(true); }
public unsafe void TestWriteAssemblerCode0() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(double) }, typeof(string), true); using (var il = new GroboIL(method)) { il.Ldarg(0); il.Conv <int>(); il.Ret(); } var func = (Func <double, int>)method.CreateDelegate(typeof(Func <double, int>)); Console.WriteLine(func(3000000000)); var pointer = DynamicMethodInvokerBuilder.DynamicMethodPointerExtractor(method); var b = (byte *)pointer; for (int i = 0; i < 20; ++i) { for (int j = 0; j < 10; ++j) { Console.Write(string.Format("{0:X2} ", *b++)); } Console.WriteLine(); } }
private static void EmitDefaultTypeValue(GroboIL il, Type type) { switch (Type.GetTypeCode(type)) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Boolean: case TypeCode.Char: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: il.Ldc_I4(0); return; case TypeCode.Int64: case TypeCode.UInt64: il.Ldc_I8(0); return; case TypeCode.Single: il.Ldc_R4(0f); return; case TypeCode.Double: il.Ldc_R8(0d); return; } if (type.IsPointer || type == typeof(UIntPtr) || type == typeof(IntPtr)) { il.Ldc_IntPtr(IntPtr.Zero); il.Conv <UIntPtr>(); } else if (type.IsEnum) { EmitDefaultTypeValue(il, Enum.GetUnderlyingType(type)); } else if (type.IsValueType) { var local = il.DeclareLocal(type); il.Ldloca(local); il.Initobj(type); il.Ldloc(local); } else { il.Ldnull(); } }
public void TestZ() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(bool), typeof(float), typeof(double) }, 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.Ldc_I4(1); il.Conv <float>(); il.Add(); il.Conv <int>(); il.Ret(); Console.Write(il.GetILCode()); } }
private KeyValuePair <Delegate, IntPtr> BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode) { var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true); using (var il = new GroboIL(method)) { var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type); il.Ldarg(1); // stack: [ref result] if (typeCode == GroBufTypeCode.Decimal) { if (expectedTypeCode == GroBufTypeCode.Boolean) { il.Ldarg(0); // stack: [ref result, &temp, address] il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] il.Ldarg(0); // stack: [ref result, &temp + 8, address] il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] il.Add(); // stack: [ref result, &temp + 8, address + 8] il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] il.Or(); il.Ldc_I4(0); // stack: [ref result, value, 0] il.Conv <long>(); il.Ceq(); // stack: [ref result, value == 0] il.Ldc_I4(1); // stack: [ref result, value == 0, 1] il.Xor(); // stack: [ref result, value != 0] } else { var temp = il.DeclareLocal(typeof(decimal)); il.Ldloca(temp); // stack: [ref result, &temp] il.Ldarg(0); // stack: [ref result, &temp, address] il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] il.Stind(typeof(long)); // *temp = *address; il.Ldloca(temp); // stack: [ref result, &temp] il.Ldc_I4(8); // stack: [ref result, &temp, 8] il.Add(); // stack: [ref result, &temp + 8] il.Ldarg(0); // stack: [ref result, &temp + 8, address] il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] il.Add(); // stack: [ref result, &temp + 8, address + 8] il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] il.Stind(typeof(long)); // *(temp + 8) = *(address + 8); il.Ldloc(temp); // stack: [ref result, ref temp] switch (expectedTypeCode) { case GroBufTypeCode.Int8: il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp] break; case GroBufTypeCode.UInt8: il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp] break; case GroBufTypeCode.Int16: il.Call(decimalToInt16Method); // stack: [ref result, (short)temp] break; case GroBufTypeCode.UInt16: il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp] break; case GroBufTypeCode.Int32: il.Call(decimalToInt32Method); // stack: [ref result, (int)temp] break; case GroBufTypeCode.UInt32: il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp] break; case GroBufTypeCode.Int64: il.Call(decimalToInt64Method); // stack: [ref result, (long)temp] break; case GroBufTypeCode.UInt64: il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp] break; case GroBufTypeCode.Single: il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp] break; case GroBufTypeCode.Double: il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp] break; case GroBufTypeCode.Decimal: break; default: throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); } } } else { il.Ldarg(0); // stack: [ref result, address] EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value] if (Type == typeof(bool)) { il.Conv <long>(); il.Ldc_I4(0); // stack: [ref result, value, 0] il.Conv <long>(); il.Ceq(); // stack: [ref result, value == 0] il.Ldc_I4(1); // stack: [ref result, value == 0, 1] il.Xor(); // stack: [ref result, value != 0] } else { EmitConvertValue(il, typeCode, expectedTypeCode); } } switch (expectedTypeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Stind(typeof(byte)); // result = value break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Stind(typeof(short)); // result = value break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Stind(typeof(int)); // result = value break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Stind(typeof(long)); // result = value break; case GroBufTypeCode.Single: il.Stind(typeof(float)); // result = value break; case GroBufTypeCode.Double: il.Stind(typeof(double)); // result = value break; case GroBufTypeCode.Decimal: il.Stobj(typeof(decimal)); // result = value break; default: throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); } il.Ret(); } var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type)); return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method))); }
private static void EmitConvertValue(GroboIL il, GroBufTypeCode typeCode, GroBufTypeCode expectedTypeCode) { if (expectedTypeCode == typeCode) { return; } switch (expectedTypeCode) { case GroBufTypeCode.Int8: il.Conv <sbyte>(); break; case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Conv <byte>(); break; case GroBufTypeCode.Int16: il.Conv <short>(); break; case GroBufTypeCode.UInt16: il.Conv <ushort>(); break; case GroBufTypeCode.Int32: if (typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) { il.Conv <int>(); } break; case GroBufTypeCode.UInt32: if (typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) { il.Conv <uint>(); } break; case GroBufTypeCode.Int64: if (typeCode != GroBufTypeCode.UInt64) { if (typeCode == GroBufTypeCode.UInt8 || typeCode == GroBufTypeCode.UInt16 || typeCode == GroBufTypeCode.UInt32) { il.Conv <ulong>(); } else { il.Conv <long>(); } } break; case GroBufTypeCode.UInt64: if (typeCode != GroBufTypeCode.Int64 && typeCode != GroBufTypeCode.DateTimeNew) { if (typeCode == GroBufTypeCode.Int8 || typeCode == GroBufTypeCode.Int16 || typeCode == GroBufTypeCode.Int32) { il.Conv <long>(); } else { il.Conv <ulong>(); } } break; case GroBufTypeCode.Single: if (typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) { il.Conv_R_Un(); } il.Conv <float>(); break; case GroBufTypeCode.Double: if (typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) { il.Conv_R_Un(); } il.Conv <double>(); break; case GroBufTypeCode.Decimal: switch (typeCode) { case GroBufTypeCode.Boolean: case GroBufTypeCode.Int8: case GroBufTypeCode.Int16: case GroBufTypeCode.Int32: case GroBufTypeCode.UInt8: case GroBufTypeCode.UInt16: il.Newobj(decimalByIntConstructor); break; case GroBufTypeCode.UInt32: il.Newobj(decimalByUIntConstructor); break; case GroBufTypeCode.Int64: case GroBufTypeCode.DateTimeNew: il.Newobj(decimalByLongConstructor); break; case GroBufTypeCode.UInt64: il.Newobj(decimalByULongConstructor); break; case GroBufTypeCode.Single: il.Call(decimalByFloatMethod); break; case GroBufTypeCode.Double: il.Call(decimalByDoubleMethod); break; default: throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported"); } break; default: throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); } }
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); }
private Type BuildReaderInvoker() { var argument = Type.GetGenericArguments()[0]; var typeBuilder = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class); var reader = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private); var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private); var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(IntPtr), typeof(long) }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); // stack: [this] il.Ldarg(1); // stack: [this, reader] il.Stfld(reader); // this.reader = reader; stack: [] il.Ldarg(0); // stack: [this] il.Ldarg(2); // stack: [this, serializerId] il.Stfld(serializerId); // this.serializerId = serializerId; stack: [] il.Ret(); } var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] { typeof(byte[]) }); using (var il = new GroboIL(method)) { var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true); il.Ldarg(1); // stack: [data] il.Ldc_I4(0); // stack: [data, 0] il.Ldelema(typeof(byte)); // stack: [&data[0]] il.Stloc(pinnedData); // pinnedData = &data[0]; stack: [] var index = il.DeclareLocal(typeof(int), "index"); il.Ldc_I4(0); // stack: [0] il.Stloc(index); // index = 0; stack: [] var context = il.DeclareLocal(typeof(ReaderContext), "context"); il.Ldarg(0); // stack: [this] il.Ldfld(serializerId); // stack: [this.serializerId] il.Ldarg(1); // stack: [this.serializerId, data] il.Ldlen(); // stack: [this.serializerId, data.Length] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0, 0] il.Newobj(typeof(ReaderContext).GetConstructor(new[] { typeof(long), typeof(int), typeof(int), typeof(int) })); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)] il.Stloc(context); // context = new ReaderContext(..); stack: [] var result = il.DeclareLocal(argument, "result"); il.Ldloc(pinnedData); // stack: [data] il.Conv <IntPtr>(); // stack: [(IntPtr)data] il.Ldloca(index); // stack: [(IntPtr)data, ref index] il.Ldloca(result); // stack: [(IntPtr)data, ref index, ref result] il.Ldloc(context); // stack: [(IntPtr)data, ref index, ref result, context] il.Ldarg(0); // stack: [(IntPtr)data, ref index, ref result, context, this] il.Ldfld(reader); // stack: [(IntPtr)data, ref index, ref result, context, this.reader] var parameterTypes = new[] { typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: [] il.FreePinnedLocal(pinnedData); // pinnedData = null; stack: [] var retLabel = il.DefineLabel("ret"); il.Ldarg(1); // stack: [data] il.Ldlen(); // stack: [data.Length] il.Ldloc(index); // stack: [data.Length, index] il.Beq(retLabel); // if(data.Length == index) goto ret; stack: [] il.Ldstr("Encountered extra data"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(retLabel); il.Ldloc(result); il.Ret(); } return(typeBuilder.CreateType()); }
private static void EmitConvertValueChecked(GroboIL il, Type from, Type to) { var fromTypeCode = Type.GetTypeCode(from); var toTypeCode = Type.GetTypeCode(to); switch (fromTypeCode) { case TypeCode.DBNull: case TypeCode.DateTime: case TypeCode.Decimal: case TypeCode.Empty: case TypeCode.Object: case TypeCode.String: throw new NotSupportedException("Cast from type '" + from + "' to type '" + to + "' is not supported"); } if (toTypeCode == fromTypeCode) { return; } switch (toTypeCode) { case TypeCode.SByte: il.Conv_Ovf <sbyte>(from.Unsigned()); break; case TypeCode.Byte: case TypeCode.Boolean: il.Conv_Ovf <byte>(from.Unsigned()); break; case TypeCode.Int16: il.Conv_Ovf <short>(from.Unsigned()); break; case TypeCode.UInt16: il.Conv_Ovf <ushort>(from.Unsigned()); break; case TypeCode.Int32: if (fromTypeCode == TypeCode.UInt32 || fromTypeCode == TypeCode.Int64 || fromTypeCode == TypeCode.UInt64 || fromTypeCode == TypeCode.Double || fromTypeCode == TypeCode.Single /* || fromTypeCode == TypeCode.DateTime*/) { il.Conv_Ovf <int>(from.Unsigned()); } break; case TypeCode.UInt32: if (fromTypeCode == TypeCode.SByte || fromTypeCode == TypeCode.Int16 || fromTypeCode == TypeCode.Int32 || fromTypeCode == TypeCode.Int64 || fromTypeCode == TypeCode.UInt64 || fromTypeCode == TypeCode.Double || fromTypeCode == TypeCode.Single /* || fromTypeCode == TypeCode.DateTime*/) { il.Conv_Ovf <uint>(from.Unsigned()); } break; case TypeCode.Int64: switch (fromTypeCode) { case TypeCode.Double: case TypeCode.Single: case TypeCode.UInt64: il.Conv_Ovf <long>(from.Unsigned()); break; case TypeCode.UInt32: case TypeCode.Char: case TypeCode.UInt16: case TypeCode.Byte: il.Conv <ulong>(); break; default: il.Conv <long>(); break; } break; case TypeCode.UInt64: switch (fromTypeCode) { case TypeCode.Double: case TypeCode.Single: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: il.Conv_Ovf <ulong>(from.Unsigned()); break; case TypeCode.UInt32: case TypeCode.Char: case TypeCode.UInt16: case TypeCode.Byte: il.Conv <ulong>(); break; } break; case TypeCode.Single: if (fromTypeCode == TypeCode.UInt64 || fromTypeCode == TypeCode.UInt32) { il.Conv_R_Un(); } il.Conv <float>(); break; case TypeCode.Double: if (fromTypeCode == TypeCode.UInt64 || fromTypeCode == TypeCode.UInt32) { il.Conv_R_Un(); } il.Conv <double>(); break; default: throw new NotSupportedException("Type with type code '" + toTypeCode + "' is not supported"); } }
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 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)); }