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