예제 #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
        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());
        }
예제 #3
0
        public void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext)
        {
            var method = new DynamicMethod("Write_" + Type.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                Type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)
            }, writerTypeBuilderContext.Module, true);

            writerTypeBuilderContext.SetWriterMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new WriterMethodBuilderContext(writerTypeBuilderContext, il);

                var notEmptyLabel = il.DefineLabel("notEmpty");
                if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty
                {
                    context.WriteNull();                // Write null & return
                }
                il.MarkLabel(notEmptyLabel);            // Now we know that obj is not empty

                if (!Type.IsValueType && IsReference && writerTypeBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences))
                {
                    // Pack reference
                    var index = il.DeclareLocal(typeof(int));
                    context.LoadIndex();                                                                                             // stack: [external index]
                    context.LoadContext();                                                                                           // stack: [external index, context]
                    il.Ldfld(WriterContext.StartField);                                                                              // stack: [external index, context.start]
                    il.Sub();                                                                                                        // stack: [external index - context.start]
                    il.Stloc(index);                                                                                                 // index = external index - context.start; stack: []
                    context.LoadContext();                                                                                           // stack: [context]
                    il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance));                // stack: [context.objects]
                    context.LoadObj();                                                                                               // stack: [context.objects, obj]
                    var reference = il.DeclareLocal(typeof(int));
                    il.Ldloca(reference);                                                                                            // stack: [context.objects, obj, ref reference]
                    int dummy;
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.TryGetValue(null, out dummy))); // stack: [context.object.TryGetValue(obj, out reference)]
                    var storeLocationLabel = il.DefineLabel("storeLocation");
                    il.Brfalse(storeLocationLabel);
                    // Current object is in dict
                    il.Ldloc(index);
                    il.Ldloc(reference);                             // stack: [index, reference]
                    var skipSelfLabel = il.DefineLabel("skipSelf");
                    il.Beq(skipSelfLabel);                           // if(index == reference) goto skipSelf; stack: []
                    il.Ldloc(index);                                 // stack: [index]
                    il.Ldloc(reference);                             // stack: [index, reference]
                    var badReferenceLabel = il.DefineLabel("badReference");
                    il.Blt(badReferenceLabel, false);                // if(index < reference) goto badReference; stack: []
                    context.WriteTypeCode(GroBufTypeCode.Reference); // result[index++] = GroBufTypeCode.Reference
                    context.GoToCurrentLocation();                   // stack: [&result[index]]
                    il.Ldloc(reference);                             // stack: [&result[index], reference]
                    il.Stind(typeof(int));                           // *(int *)&result[index] = reference
                    context.IncreaseIndexBy4();                      // index += 4
                    il.Ret();
                    il.MarkLabel(badReferenceLabel);
                    il.Ldstr("Bad reference");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    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);
                    il.MarkLabel(skipSelfLabel);
                }

                WriteNotEmpty(context); // Write obj
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(WriterDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            writerTypeBuilderContext.SetWriterPointer(Type, pointer, @delegate);
        }