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)); }