예제 #1
0
        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>)));
        }
예제 #2
0
        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));
        }