示例#1
0
        protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context)
        {
            var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer);
            var il = context.Il;

            context.LoadField(customSerializerField); // stack: [customSerializer]
            context.LoadObj();                        // stack: [customSerializer, obj]
            if (Type.IsValueType)
            {
                il.Box(Type);                                                                                                          // stack: [customSerializer, (object)obj]
            }
            context.LoadWriteEmpty();                                                                                                  // stack: [customSerializer, (object)obj, writeEmpty]
            context.LoadContext();                                                                                                     // stack: [customSerializer, (object)obj, writeEmpty, context]
            il.Call(HackHelpers.GetMethodDefinition <IGroBufCustomSerializer>(serializer => serializer.CountSize(null, false, null))); // stack: [customSerializer.CountSize((object)obj, writeEmpty, context)]

            var countLengthLabel = il.DefineLabel("countLength");

            il.Dup();                    // stack: [size, size]
            il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size]
            il.Pop();                    // stack: []
            context.ReturnForNull();
            il.Ret();
            il.MarkLabel(countLengthLabel);
            il.Ldc_I4(5); // stack: [size, 5]
            il.Add();     // stack: [size + 5]
        }
示例#2
0
        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);
        }
        protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context)
        {
            var il = context.Il;

            il.Ldc_I4(0); // stack: [0 = size]

            var dataMembers = context.Context.GetDataMembers(Type);

            foreach (var member in dataMembers)
            {
                if (Type.IsValueType)
                {
                    context.LoadObjByRef(); // stack: [size, ref obj]
                }
                else
                {
                    context.LoadObj(); // stack: [size, obj]
                }
                Type memberType;
                switch (member.Member.MemberType)
                {
                case MemberTypes.Property:
                    var property = (PropertyInfo)member.Member;
                    var getter   = property.GetGetMethod(true);
                    if (getter == null)
                    {
                        throw new MissingMethodException(Type.Name, property.Name + "_get");
                    }
                    il.Call(getter, Type); // stack: [size, obj.prop]
                    memberType = property.PropertyType;
                    break;

                case MemberTypes.Field:
                    var field = (FieldInfo)member.Member;
                    il.Ldfld(field); // stack: [size, obj.field]
                    memberType = field.FieldType;
                    break;

                default:
                    throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported");
                }
                il.Ldc_I4(0);                        // stack: [size, obj.member, false]
                context.LoadContext();               // stack: [size, obj.member, false, context]
                context.CallSizeCounter(memberType); // stack: [size, writers[i](obj.member, false, context) = memberSize]
                il.Dup();                            // stack: [size, memberSize, memberSize]
                var nextLabel = il.DefineLabel("next");
                il.Brfalse(nextLabel);               // if(memberSize = 0) goto next; stack: [size, memberSize]

                il.Ldc_I4(8);                        // stack: [size, memberSize, 8]
                il.Add();                            // stack: [size, memberSize + 8]
                il.MarkLabel(nextLabel);
                il.Add();                            // stack: [size + curSize]
            }

            if (!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects))
            {
                var countLengthLabel = il.DefineLabel("countLength");
                il.Dup();                    // stack: [size, size]
                il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size]
                il.Pop();                    // stack: []
                context.ReturnForNull();
                il.Ret();
                il.MarkLabel(countLengthLabel);
            }
            il.Ldc_I4(5); // stack: [size, 5]
            il.Add();     // stack: [size + 5]
        }
        protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context)
        {
            var il = context.Il;

            var counters      = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair <Delegate, IntPtr>(null, IntPtr.Zero) : GetCounter(context, type1)).ToArray();
            var countersField = context.Context.InitConstField(Type, 0, counters.Select(pair => pair.Value).ToArray());

            context.Context.InitConstField(Type, 1, counters.Select(pair => pair.Key).ToArray());

            il.Ldfld(typeof(GroBufHelpers).GetField("LeafTypeHandles", BindingFlags.Public | BindingFlags.Static)); // stack: [LeafTypeHandles]
            context.LoadObj();                                                                                      // stack: [LeafTypeHandles, obj]
            il.Call(getTypeMethod);                                                                                 // stack: [LeafTypeHandles, obj.GetType()]
            var type = il.DeclareLocal(typeof(Type));

            il.Dup();                                       // stack: [LeafTypeHandles, obj.GetType(), obj.GetType()]
            il.Stloc(type);                                 // type = obj.GetType(); stack: [LeafTypeHandles, obj.GetType()]
            il.Call(typeTypeHandleProperty.GetGetMethod()); // stack: [LeafTypeHandles, obj.GetType().TypeHandle]
            var typeHandle = il.DeclareLocal(typeof(RuntimeTypeHandle));

            il.Stloc(typeHandle);                                                              // typeHandle = obj.GetType().TypeHandle; stack: [LeafTypeHandles]
            il.Ldloca(typeHandle);                                                             // stack: [LeafTypeHandles, ref typeHandle]
            il.Call(runtimeTypeHandleValueProperty.GetGetMethod(), typeof(RuntimeTypeHandle)); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value]
            var handle = il.DeclareLocal(typeof(IntPtr));

            il.Dup();                   // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value, obj.GetType().TypeHandle.Value]
            il.Stloc(handle);           // handle = obj.GetType().TypeHandle.Value; stack: [LeafTypeHandles, handle]
            il.Ldc_I4(counters.Length); // stack: [LeafTypeHandles, handle, LeafTypeHandles.Length]
            il.Rem(true);               // stack: [LeafTypeHandles, handle % LeafTypeHandles.Length]
            var index = il.DeclareLocal(typeof(int));

            il.Conv <int>();           // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length)]
            il.Dup();                  // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length), (int)(handle % LeafTypeHandles.Length)]
            il.Stloc(index);           // index = (int)(handle % LeafTypeHandles.Length); stack: [LeafTypeHandles, index]
            il.Ldelem(typeof(IntPtr)); // stack: [LeafTypeHandles[index]]
            il.Ldloc(handle);          // stack: [LeafTypeHandles[index], handle]
            var tryAsArrayLabel = il.DefineLabel("tryAsArray");

            il.Bne_Un(tryAsArrayLabel);       // if(LeafTypeHandles[index] != handle) goto tryAsArray; stack: []
            context.LoadObj();                // stack: [obj]
            context.LoadWriteEmpty();         // stack: [obj, writeEmpty]
            context.LoadContext();            // stack: [obj, writeEmpty, context]
            context.LoadField(countersField); // stack: [obj, writeEmpty, context, counters]
            il.Ldloc(index);                  // stack: [obj, writeEmpty, context, counters, index]
            il.Ldelem(typeof(IntPtr));        // stack: [obj, writeEmpty, context, counters[index]]
            var parameterTypes = new[] { typeof(object), typeof(bool), typeof(WriterContext) };

            il.Calli(CallingConventions.Standard, typeof(int), parameterTypes); // stack: [counters[index](obj, writeEmpty)]
            il.Ret();

            il.MarkLabel(tryAsArrayLabel);
            il.Ldloc(type);                              // stack: [obj.GetType()]
            il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray]
            var returnForNullLabel = il.DefineLabel("returnForNull");

            il.Brfalse(returnForNullLabel);
            context.LoadObj();                                                   // stack: [obj]
            context.LoadWriteEmpty();                                            // stack: [obj, writeEmpty]
            context.LoadContext();                                               // stack: [obj, writeEmpty, context]
            context.LoadField(countersField);                                    // stack: [obj, writeEmpty, context, counters]
            il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, context, counters, index of typeof(object[])]
            il.Ldelem(typeof(IntPtr));                                           // stack: [obj, writeEmpty, context, counters[index of typeof(object[])]]
            parameterTypes = new[] { typeof(object), typeof(bool), typeof(WriterContext) };
            il.Calli(CallingConventions.Standard, typeof(int), parameterTypes);  // stack: [counters[index of typeof(object[])](obj, writeEmpty)]
            il.Ret();

            il.MarkLabel(returnForNullLabel);
            context.ReturnForNull();
        }