protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { context.LoadObjByRef(); // stack: [&obj] context.Il.Call(Type.GetProperty("HasValue").GetGetMethod()); // stack: obj.HasValue context.Il.Brtrue(notEmptyLabel); // if(obj.HasValue) goto notEmpty; return(true); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { int[] values; ulong[] hashCodes; EnumHelpers.BuildHashCodesTable(Type, out values, out hashCodes); var hashCodesField = context.Context.InitConstField(Type, 0, hashCodes); var valuesField = context.Context.InitConstField(Type, 1, values); var il = context.Il; context.LoadField(valuesField); // stack: [values] context.LoadObj(); // stack: [values, obj] il.Ldc_I4(values.Length); // stack: [values, obj, values.Length] il.Rem(true); // stack: [values, obj % values.Length] il.Ldelem(typeof(int)); // stack: [values[obj % values.Length]] context.LoadObj(); // stack: [values[obj % values.Length], obj] il.Ceq(); // stack: [values[obj % values.Length] == obj] var countAsIntLabel = il.DefineLabel("countAsInt"); il.Brfalse(countAsIntLabel); // if(values[obj % values.Length] != obj) goto countAsInt context.LoadField(hashCodesField); // stack: [hashCodes] context.LoadObj(); // stack: [hashCodes, obj] il.Ldc_I4(hashCodes.Length); // stack: [hashCodes, obj, hashCodes.Length] il.Rem(true); // stack: [hashCodes, obj % hashCodes.Length] il.Ldelem(typeof(long)); // stack: [hashCodes[obj % hashCodes.Length] = hashCode] il.Brfalse(countAsIntLabel); // if(hashCode == 0) goto countAsInt; il.Ldc_I4(9); // stack: [9] il.Ret(); // return 9; il.MarkLabel(countAsIntLabel); il.Ldc_I4(5); // stack: [5] }
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] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; context.LoadObjByRef(); // stack: [&obj] il.Call(Type.GetProperty("Value").GetGetMethod()); // stack: [obj.Value] context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] context.LoadContext(); // stack: [obj.Value, writeEmpty, context] context.CallSizeCounter(Type.GetGenericArguments()[0]); // stack: [counter(obj.Value, writeEmpty, context)] }
/// <summary> /// Checks whether <c>obj</c> is empty /// </summary> /// <param name="context">Current context</param> /// <param name="notEmptyLabel">Label where to go if <c>obj</c> is not empty</param> /// <returns>true if <c>obj</c> can be empty</returns> protected virtual bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { if (Type.IsValueType) { return(false); } context.LoadObj(); // stack: [obj] context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; return(true); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length context.LoadObjByRef(); // stack: [5, ref obj] il.Ldfld(countField); // stack: [5, obj._count] CountArraySize(elementType, il); // stack: [5, obj length] il.Add(); // stack: [5 + obj length] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length context.LoadObj(); // stack: [5, obj] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [5, obj.Count] CountArraySize(elementType, il); // stack: [5, obj length] il.Add(); // stack: [5 + obj length] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; context.LoadObj(); // stack: [obj] il.Call(lengthPropertyGetter); // stack: [obj.Length] il.Ldc_I4(1); // stack: [obj.Length, 1] il.Shl(); // stack: [obj.Length << 1] il.Ldc_I4(5); // stack: [obj.Length << 1, 5] il.Add(); // stack: [obj.Length << 1 + 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(4); // stack: [4] context.LoadObj(); // stack: [4, obj] il.Ldfld(Type.GetField("m_Family", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [4, obj.m_Family] il.Ldc_I4((int)AddressFamily.InterNetworkV6); // stack: [4, obj.m_Family, AddressFamily.InterNetworkV6] il.Ceq(); // stack: [4, obj.m_Family == AddressFamily.InterNetworkV6] il.Ldc_I4(1); // stack: [4, obj.m_Family == AddressFamily.InterNetworkV6, 1] il.Shl(); // stack: [4, (obj.m_Family == AddressFamily.InterNetworkV6) << 1] il.Shl(); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1)] il.Ldc_I4(5); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1), 5] il.Add(); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1) + 5] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length var count = il.DeclareLocal(typeof(int)); context.LoadObj(); // stack: [9, obj] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj.Count] il.Stloc(count); // count = obj.Count; stack: [9] il.Ldloc(count); // stack: [9, count] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [9] var items = il.DeclareLocal(elementType.MakeArrayType()); context.LoadObj(); // stack: [9, obj] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj._items] il.Stloc(items); // items = obj._items; stack: [9] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [9, 0] il.Stloc(i); // i = 0; stack: [9] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(items); // stack: [size, items] il.Ldloc(i); // stack: [size, items, i] il.Ldelem(elementType); il.Ldc_I4(1); // stack: [size, obj[i], true] context.LoadContext(); // stack: [size, obj[i], true, context] context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] il.Add(); // stack: [size + itemSize] il.Ldloc(count); // stack: [size, length] il.Ldloc(i); // stack: [size, length, i] il.Ldc_I4(1); // stack: [size, length, i, 1] il.Add(); // stack: [size, length, i + 1] il.Dup(); // stack: [size, length, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, length, i] il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length var doneLabel = il.DefineLabel("done"); context.LoadObjByRef(); // stack: [size, ref obj] il.Ldfld(countField); // stack: [size, obj._count] il.Brfalse(doneLabel); // if(obj._count == 0) goto done; stack: [size] var i = il.DeclareLocal(typeof(int)); var end = il.DeclareLocal(typeof(int)); context.LoadObjByRef(); // stack: [size, ref obj] il.Dup(); // stack: [size, ref obj, ref obj] il.Ldfld(offsetField); // stack: [size, ref obj, obj._offset] il.Stloc(i); // i = obj._offset; stack: [size, ref obj] il.Ldfld(countField); // stack: [size, obj._count] il.Ldloc(i); // stack: [size, obj._count, obj._offset] il.Add(); // stack: [size, obj._count + obj._offset] il.Stloc(end); // end = obj._count + obj._offset; stack: [size] var array = il.DeclareLocal(elementType.MakeArrayType()); context.LoadObjByRef(); // stack: [size, ref obj] il.Ldfld(arrayField); // stack: [size, obj._array] il.Stloc(array); // array = obj._array; stack: [size] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(array); // stack: [size, array] il.Ldloc(i); // stack: [size, array, i] il.Ldelem(elementType); // stack: [size, array[i]] il.Ldc_I4(1); // stack: [size, array[i], true] context.LoadContext(); // stack: [size, array[i], true, context] context.CallSizeCounter(elementType); // stack: [size, writer(array[i], true, context) = itemSize] il.Add(); // stack: [size + itemSize] il.Ldloc(end); // stack: [size, end] il.Ldloc(i); // stack: [size, end, i] il.Ldc_I4(1); // stack: [size, end, i, 1] il.Add(); // stack: [size, end, i + 1] il.Dup(); // stack: [size, end, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, end, i] il.Bgt(cycleStartLabel, false); // if(end > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { context.LoadObj(); // stack: [obj] if (context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) { context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; } else { var emptyLabel = context.Il.DefineLabel("empty"); context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; context.LoadObj(); // stack: [obj] context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; context.Il.MarkLabel(emptyLabel); } return(true); }
protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { context.LoadObj(); // stack: [obj] if (context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) { context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; } else { var emptyLabel = context.Il.DefineLabel("empty"); context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; context.LoadObj(); // stack: [obj] context.Il.Ldlen(); // stack: [obj.Length] context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; context.Il.MarkLabel(emptyLabel); } return(true); }
protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { context.LoadObj(); // stack: [obj] if (context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) { context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; } else { var emptyLabel = context.Il.DefineLabel("empty"); context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; context.LoadObj(); // stack: [obj] context.Il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashtableCountFieldNames)); // stack: [obj.Count] context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; context.Il.MarkLabel(emptyLabel); } return(true); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); var il = context.Il; switch (typeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Ldc_I4(2); break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Ldc_I4(3); break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Ldc_I4(5); break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Ldc_I4(9); break; case GroBufTypeCode.Single: il.Ldc_I4(5); break; case GroBufTypeCode.Double: il.Ldc_I4(9); break; case GroBufTypeCode.Decimal: il.Ldc_I4(17); break; default: throw new NotSupportedException("Type '" + Type + "' is not supported"); } }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; var argument = Type.GetGenericArguments()[0]; context.LoadObj(); // stack: [obj] var factoryField = Type.GetField("m_valueFactory", BindingFlags.Instance | BindingFlags.NonPublic); il.Ldfld(factoryField); // stack: [obj.m_valueFactory] var factory = il.DeclareLocal(typeof(Func <>).MakeGenericType(argument)); il.Dup(); il.Stloc(factory); // factory = obj.m_valueFactory; stack: [factory] var countUsual = il.DefineLabel("countUsual"); il.Brfalse(countUsual); // if(factory == null) goto countUsual; stack: [] il.Ldloc(factory); // stack: [factory] string targetFieldName = GroBufHelpers.IsMono ? "m_target" : "_target"; il.Ldfld(typeof(Delegate).GetField(targetFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [factory.target] var rawData = il.DeclareLocal(typeof(RawData <>).MakeGenericType(Type.GetGenericArguments())); il.Isinst(rawData.Type); // stack: [factory.target as RawData] il.Dup(); il.Stloc(rawData); // rawData = factory.target as RawData; stack: [rawData] il.Brfalse(countUsual); // if(!(rawData is RawData)) goto countUsual; stack: [] il.Ldloc(rawData); // stack: [rawData] il.Ldfld(rawData.Type.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.serializerId] context.LoadSerializerId(); // stack: [rawData.serializerId, context.serializerId] il.Bne_Un(countUsual); // if(rawData.serializerId != context.serializerId) goto countUsual; stack: [] il.Ldloc(rawData); // stack: [rawData] il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] il.Ldlen(); // stack: [rawData.data.Length] il.Ret(); il.MarkLabel(countUsual); context.LoadObj(); // stack: [obj] il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] context.LoadContext(); // stack: [obj.Value, writeEmpty, context] context.CallSizeCounter(argument); // stack: [counter(obj.Value, writeEmpty, context)] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(5); // stack: [5 = size] var genericArguments = Type.GetGenericArguments(); for (int i = 0; i < genericArguments.Length; ++i) { var property = Type.GetProperty(i == 7 ? "Rest" : "Item" + (i + 1)); var getter = property.GetGetMethod(); context.LoadObj(); // stack: [size, obj] il.Call(getter); // stack: [size, obj.Item{i}] il.Ldc_I4(1); // stack: [size, obj.Item{i}, true] context.LoadContext(); // stack: [size, obj.Item{i}, true, context] context.CallSizeCounter(genericArguments[i]); // stack: [size, writers[i](obj.Item{i}, true, context) = memberSize] il.Add(); // stack: [size + memberSize => size] } }
protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) { var il = context.Il; context.LoadObjByRef(); // stack: [ref obj] il.Ldfld(arrayField); // stack: [obj._array] if (context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) { il.Brtrue(notEmptyLabel); // if(obj._array != null) goto notEmpty; } else { var emptyLabel = il.DefineLabel("empty"); il.Brfalse(emptyLabel); // if(obj._array == null) goto empty; context.LoadObjByRef(); // stack: [ref obj] il.Ldfld(countField); // stack: [obj._count] il.Brtrue(notEmptyLabel); // if(obj._count != 0) goto notEmpty; il.MarkLabel(emptyLabel); } return(true); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length var length = il.DeclareLocal(typeof(int)); context.LoadObj(); // stack: [9, obj] il.Ldlen(); // stack: [9, obj.Length] il.Stloc(length); // length = obj.Length; stack: [9] var doneLabel = il.DefineLabel("done"); il.Ldloc(length); // stack: [size, length] il.Brfalse(doneLabel); // if(length == 0) goto done; stack: [size] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [size, 0] il.Stloc(i); // i = 0; stack: [size] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadObj(); // stack: [size, obj] il.Ldloc(i); // stack: [size, obj, i] il.Ldelem(elementType); il.Ldc_I4(1); // stack: [size, obj[i], true] context.LoadContext(); // stack: [size, obj[i], true, context] context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] il.Add(); // stack: [size + itemSize] il.Ldloc(length); // stack: [size, length] il.Ldloc(i); // stack: [size, length, i] il.Ldc_I4(1); // stack: [size, length, i, 1] il.Add(); // stack: [size, length, i + 1] il.Dup(); // stack: [size, length, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, length, i] il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
private static KeyValuePair <Delegate, IntPtr> GetCounter(SizeCounterMethodBuilderContext context, Type type) { var method = new DynamicMethod("CastTo_" + type.Name + "_AndCount_" + Guid.NewGuid(), typeof(int), new[] { typeof(object), typeof(bool), typeof(WriterContext) }, context.Context.Module, true); using (var il = new GroboIL(method)) { il.Ldarg(0); // stack: [obj] if (type.IsValueType) { il.Unbox_Any(type); // stack: [(type)obj] } else { il.Castclass(type); // stack: [(type)obj] } il.Ldarg(1); // stack: [(type)obj, writeEmpty] il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] context.CallSizeCounter(il, type); il.Ret(); } var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate <object>)); return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method))); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + hashset count context.LoadObj(); // stack: [size, obj] var count = il.DeclareLocal(typeof(int)); il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetCountFieldNames)); // stack: [size, obj.m_lastIndex] il.Dup(); il.Stloc(count); // count = obj.m_lastIndex; stack: [size, count] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(!count) goto done; stack: [size] context.LoadObj(); // stack: [size, obj] var slotType = Type.GetNestedType(PlatformHelpers.HashSetSlotTypeName, BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); var slots = il.DeclareLocal(slotType.MakeArrayType()); il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetSlotsFieldNames)); il.Stloc(slots); var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [9, 0] il.Stloc(i); // i = 0; stack: [9] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(slots); // stack: [size, slots] il.Ldloc(i); // stack: [size, slots, i] il.Ldelema(slotType); // stack: [size, &slots[i]] il.Dup(); // stack: [size, &slots[i], &slots[i]] var slot = il.DeclareLocal(slotType.MakeByRefType()); il.Stloc(slot); // slot = &slots[i]; stack: [size, slot] if (PlatformHelpers.IsDotNet50OrGreater) { il.Ldfld(slotType.GetField("Next")); // stack: [size, slot.Next] il.Ldc_I4(-1); // stack: [size, slot.Next, -1] } else { il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, slot.hashCode] il.Ldc_I4(0); // stack: [size, slot.hashCode, 0] } var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [size] il.Ldloc(slot); // stack: [size, slot] il.Ldfld(slotType.GetField(PlatformHelpers.HashSetSlotValueFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); // stack: [size, slot.value] il.Ldc_I4(1); // stack: [size, slot.value, true] context.LoadContext(); // stack: [size, slot.value, true, context] context.CallSizeCounter(elementType); // stack: [size, writer(slot.value, true, context) = valueSize] il.Add(); // stack: [size + valueSize] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [size, count] il.Ldloc(i); // stack: [size, count, i] il.Ldc_I4(1); // stack: [size, count, i, 1] il.Add(); // stack: [size, count, i + 1] il.Dup(); // stack: [size, count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count context.LoadObj(); // stack: [size, obj] il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] context.LoadObj(); // stack: [size, obj] var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); var buckets = il.DeclareLocal(bucketType.MakeArrayType()); var bucketsField = Type.GetField("buckets", BindingFlags.Instance | BindingFlags.NonPublic); il.Ldfld(bucketsField); // stack: [size, obj.buckets] il.Stloc(buckets); // buckets = obj.buckets; stack: [size] var length = il.DeclareLocal(typeof(int)); il.Ldloc(buckets); // stack: [size, buckets] il.Ldlen(); // stack: [size, buckets.Length] il.Stloc(length); // length = buckets.Length var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [9, 0] il.Stloc(i); // i = 0; stack: [9] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(buckets); // stack: [size, buckets] il.Ldloc(i); // stack: [size, buckets, i] il.Ldelema(bucketType); // stack: [size, &buckets[i]] il.Dup(); // stack: [size, &entries[i], &buckets[i]] var bucket = il.DeclareLocal(bucketType.MakeByRefType()); il.Stloc(bucket); // bucket = &buckets[i]; stack: [size, bucket] il.Ldfld(bucketType.GetField("key", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.key] il.Dup(); // stack: [size, bucket.key, bucket.key] var key = il.DeclareLocal(typeof(object)); il.Stloc(key); // key = bucket.key; stack: [size, key] var nextLabel = il.DefineLabel("next"); il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [size] il.Ldloc(key); // stack: [size, key] context.LoadObj(); // stack: [size, key, obj] il.Ldfld(bucketsField); // stack: [size, key, obj.buckets] il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [size] il.Ldloc(key); // stack: [size, key] il.Ldc_I4(1); // stack: [size, key, true] context.LoadContext(); // stack: [size, key, true, context] context.CallSizeCounter(typeof(object)); // stack: [size, writer(key, true, context) = keySize] il.Add(); // stack: [size + keySize] il.Ldloc(bucket); // stack: [size, bucket] il.Ldfld(bucketType.GetField("val", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.val] il.Ldc_I4(1); // stack: [size, bucket.val, true] context.LoadContext(); // stack: [size, bucket.val, true, context] context.CallSizeCounter(typeof(object)); // stack: [size, writer(bucket.val, true, context) = valueSize] il.Add(); // stack: [size + valueSize] il.MarkLabel(nextLabel); il.Ldloc(length); // stack: [size, length] il.Ldloc(i); // stack: [size, length, i] il.Ldc_I4(1); // stack: [size, length, i, 1] il.Add(); // stack: [size, length, i + 1] il.Dup(); // stack: [size, length, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, length, i] il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9] }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var il = context.Il; il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count context.LoadObj(); // stack: [size, obj] var count = il.DeclareLocal(typeof(int)); // traverse all buckets il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] il.Stloc(count); // count = obj.Count; stack: [size] var doneLabel = il.DefineLabel("done"); il.Ldloc(count); // stack: [size, count] il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] context.LoadObj(); // stack: [size, obj] var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); var entries = il.DeclareLocal(entryType.MakeArrayType()); il.Ldfld(Type.GetField("entries", BindingFlags.Instance | BindingFlags.NonPublic)); il.Stloc(entries); var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [9, 0] il.Stloc(i); // i = 0; stack: [9] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(entries); // stack: [size, entries] il.Ldloc(i); // stack: [size, entries, i] il.Ldelema(entryType); // stack: [size, &entries[i]] il.Dup(); // stack: [size, &entries[i], &entries[i]] var entry = il.DeclareLocal(entryType.MakeByRefType()); il.Stloc(entry); // entry = &entries[i]; stack: [size, entry] il.Ldfld(entryType.GetField("hashCode")); // stack: [size, entry.hashCode] il.Ldc_I4(0); // stack: [size, entry.hashCode, 0] var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [size] il.Ldloc(entry); // stack: [size, entry] il.Ldfld(entryType.GetField("key")); // stack: [size, entry.key] il.Ldc_I4(1); // stack: [size, entry.key, true] context.LoadContext(); // stack: [size, entry.key, true, context] context.CallSizeCounter(keyType); // stack: [size, writer(entry.key, true, context) = keySize] il.Add(); // stack: [size + keySize] il.Ldloc(entry); // stack: [size, entry] il.Ldfld(entryType.GetField("value")); // stack: [size, entry.value] il.Ldc_I4(1); // stack: [size, entry.value, true] context.LoadContext(); // stack: [size, entry.value, true, context] context.CallSizeCounter(valueType); // stack: [size, writer(entry.value, true, context) = valueSize] il.Add(); // stack: [size + valueSize] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [size, count] il.Ldloc(i); // stack: [size, count, i] il.Ldc_I4(1); // stack: [size, count, i, 1] il.Add(); // stack: [size, count, i + 1] il.Dup(); // stack: [size, count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [size, count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] il.MarkLabel(doneLabel); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { // TODO call sub size counters context.Il.Ldc_I4(1 + 9 + 3); // stack: [13] }
protected abstract void CountSizeNotEmpty(SizeCounterMethodBuilderContext context);
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(); }
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) { context.Il.Ldc_I4(17); // stack: [17] }