protected override bool CheckEmpty(WriterMethodBuilderContext 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(WriterMethodBuilderContext 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 bool CheckEmpty(WriterMethodBuilderContext 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.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; context.Il.MarkLabel(emptyLabel); } return(true); }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Guid); il.Ldc_I4(16); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] il.Stind(typeof(long)); // result[index] = (int64)*obj context.IncreaseIndexBy8(); // index = index + 8 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldc_I4(8); // stack: [&result[index], &obj, 8] il.Add(); // stack: [&result[index], &obj + 8] il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) context.IncreaseIndexBy8(); // index = index + 8 }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Tuple); var start = il.DeclareLocal(typeof(int)); context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Dup(); // stack: [ref index, index, index] il.Stloc(start); // start = index; stack: [ref index, index] il.Ldc_I4(4); // stack: [ref index, index, 4] il.Add(); // stack: [ref index, index + 4] il.Stind(typeof(int)); // index = index + 4; stack: [] 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: [obj] il.Call(getter); // stack: [obj.Item{i}] il.Ldc_I4(1); // stack: [obj.Item{i}, true] context.LoadResult(); // stack: [obj.Item{i}, true, result] context.LoadIndexByRef(); // stack: [obj.Item{i}, true, result, ref index] context.LoadContext(); // stack: [obj.Item{i}, true, result, ref index, context] context.CallWriter(genericArguments[i]); // writer<i>(obj.Item{i}, true, result, ref index, context); stack: [] } context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result[start]] context.LoadIndex(); // stack: [result[start], index] il.Ldloc(start); // stack: [result[start], index, start] il.Sub(); // stack: [result[start], index - start] il.Ldc_I4(5); // stack: [result[start], index - start, 4] il.Sub(); // stack: [result[start], index - start - 4 => length] il.Stind(typeof(int)); // result[start] = length; stack: [] }
protected override bool CheckEmpty(WriterMethodBuilderContext 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 WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.DateTimeOffset); context.LoadObjByRef(); // stack: [obj] il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.DateTimeOffsetDateTimeFieldNames)); // stack: [obj.m_dateTime] context.LoadWriteEmpty(); // stack: [obj.m_dateTime, writeEmpty] context.LoadResult(); // stack: [obj.m_dateTime, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj.m_dateTime, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj.m_dateTime, writeEmpty, result, ref index, context] context.CallWriter(typeof(DateTime)); // writer(obj.m_dateTime, writeEmpty, result, ref index, context) context.LoadObjByRef(); // stack: [obj] il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.DateTimeOffsetOffsetMinutesFieldNames)); // stack: [obj.m_offsetMinutes] context.LoadWriteEmpty(); // stack: [obj.m_offsetMinutes, writeEmpty] context.LoadResult(); // stack: [obj.m_offsetMinutes, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index, context] context.CallWriter(typeof(short)); // writer(obj.m_offsetMinutes, writeEmpty, result, ref index, context) }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.DateTimeOffset); context.LoadObjByRef(); // stack: [obj] il.Ldfld(Type.GetField("m_dateTime", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_dateTime] context.LoadWriteEmpty(); // stack: [obj.m_dateTime, writeEmpty] context.LoadResult(); // stack: [obj.m_dateTime, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj.m_dateTime, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj.m_dateTime, writeEmpty, result, ref index, context] context.CallWriter(typeof(DateTime)); // writer(obj.m_dateTime, writeEmpty, result, ref index, context) context.LoadObjByRef(); // stack: [obj] il.Ldfld(Type.GetField("m_offsetMinutes", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_offsetMinutes] context.LoadWriteEmpty(); // stack: [obj.m_offsetMinutes, writeEmpty] context.LoadResult(); // stack: [obj.m_offsetMinutes, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index, context] context.CallWriter(typeof(short)); // writer(obj.m_offsetMinutes, writeEmpty, result, ref index, context) }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Dictionary); context.LoadIndex(); // stack: [index] var start = context.LocalInt; il.Stloc(start); // start = index il.Ldc_I4(8); // data length + dict size = 8 context.AssertLength(); context.IncreaseIndexBy4(); // index = index + 4 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObj(); // stack: [&result[index], obj] il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] context.LoadObj(); // stack: [obj] // traverse all buckets il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.DictionaryCountFieldNames)); // stack: [obj.count] var count = il.DeclareLocal(typeof(int)); il.Stloc(count); // count = obj.count; stack: [] var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Ldloc(count); // stack: [count] il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] context.LoadObj(); // stack: [obj] var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); var entries = il.DeclareLocal(entryType.MakeArrayType()); il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.DictionaryEntriesFieldNames)); // stack: [obj.entries] il.Stloc(entries); // entries = obj.entries; stack: [] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(entries); // stack: [entries] il.Ldloc(i); // stack: [entries, i] il.Ldelema(entryType); // stack: [&entries[i]] il.Dup(); // stack: [&entries[i], &entries[i]] var entry = il.DeclareLocal(entryType.MakeByRefType()); il.Stloc(entry); // entry = &entries[i]; stack: [entry] il.Ldfld(entryType.GetField("hashCode")); // stack: [entry.hashCode] il.Ldc_I4(0); // stack: [entry.hashCode, 0] var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [] il.Ldloc(entry); // stack: [entry] il.Ldfld(entryType.GetField("key")); // stack: [entry.key] il.Ldc_I4(1); // stack: [obj[i].key, true] context.LoadResult(); // stack: [obj[i].key, true, result] context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] context.CallWriter(keyType); // write<keyType>(obj[i].key, true, result, ref index, context); stack: [] il.Ldloc(entry); // stack: [entry] il.Ldfld(entryType.GetField("value")); // stack: [entry.value] il.Ldc_I4(1); // stack: [obj[i].value, true] context.LoadResult(); // stack: [obj[i].value, true, result] context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] context.CallWriter(valueType); // writer<valueType>(obj[i].value, true, result, ref index, context); stack: [] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [ count] il.Ldloc(i); // stack: [count, i] il.Ldc_I4(1); // stack: [count, i, 1] il.Add(); // stack: [count, i + 1] il.Dup(); // stack: [count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] context.LoadIndex(); // stack: [result + start, index] il.Ldloc(start); // stack: [result + start, index, start] il.Sub(); // stack: [result + start, index - start] il.Ldc_I4(4); // stack: [result + start, index - start, 4] il.Sub(); // stack: [result + start, index - start - 4] il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); context.WriteTypeCode(typeCode); context.GoToCurrentLocation(); // stack: [&result[index]] var il = context.Il; switch (typeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Ldc_I4(1); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(byte)); // result[index] = obj context.IncreaseIndexBy1(); // index = index + 1 break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Ldc_I4(2); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(short)); // result[index] = obj context.IncreaseIndexBy2(); // index = index + 2 break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(int)); // result[index] = obj context.IncreaseIndexBy4(); // index = index + 4 break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Ldc_I4(8); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(long)); // result[index] = obj context.IncreaseIndexBy8(); // index = index + 8 break; case GroBufTypeCode.Single: il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(float)); // result[index] = obj context.IncreaseIndexBy4(); // index = index + 4 break; case GroBufTypeCode.Double: il.Ldc_I4(8); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(double)); // result[index] = obj context.IncreaseIndexBy8(); // index = index + 8 break; case GroBufTypeCode.Decimal: il.Ldc_I4(16); context.AssertLength(); context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] il.Stind(typeof(long)); // result[index] = (int64)*obj context.IncreaseIndexBy8(); // index = index + 8 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldc_I4(8); // stack: [&result[index], &obj, 8] il.Add(); // stack: [&result[index], &obj + 8] il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) context.IncreaseIndexBy8(); // index = index + 8 break; default: throw new NotSupportedException(); } }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Array); var count = il.DeclareLocal(typeof(int)); context.LoadObj(); // stack: [obj] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] il.Stloc(count); // count = obj.Count; stack: [] var items = il.DeclareLocal(elementType.MakeArrayType()); context.LoadObj(); // stack: [obj] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._items] il.Stloc(items); // items = obj._items; stack: [] context.LoadIndex(); // stack: [index] var start = context.LocalInt; il.Stloc(start); // start = index il.Ldc_I4(8); context.AssertLength(); // data length + list size = 8 context.IncreaseIndexBy4(); // index = index + 4 context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(count); // stack: [&result[index], count] il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] context.IncreaseIndexBy4(); // index = index + 4 var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Ldloc(count); // stack: [length] il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStart = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStart); il.Ldloc(items); // stack: [items] il.Ldloc(i); // stack: [items, i] il.Ldelem(elementType); il.Ldc_I4(1); // stack: [obj[i], true] context.LoadResult(); // stack: [obj[i], true, result] context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] context.LoadContext(); // stack: [obj[i], true, result, ref index, context] context.CallWriter(elementType); // write<elementType>(obj[i], true, result, ref index, context); stack: [] il.Ldloc(count); // stack: [count] il.Ldloc(i); // stack: [count, i] il.Ldc_I4(1); // stack: [count, i, 1] il.Add(); // stack: [count, i + 1] il.Dup(); // stack: [count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [count, i] il.Bgt(cycleStart, false); // if(count > i) goto cycleStart; stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] context.LoadIndex(); // stack: [result + start, index] il.Ldloc(start); // stack: [result + start, index, start] il.Sub(); // stack: [result + start, index - start] il.Ldc_I4(4); // stack: [result + start, index - start, 4] il.Sub(); // stack: [result + start, index - start - 4] il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Array); context.LoadIndex(); // stack: [index] var start = context.LocalInt; il.Stloc(start); // start = index il.Ldc_I4(8); context.AssertLength(); // data length + hashset size = 8 context.IncreaseIndexBy4(); // index = index + 4 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObj(); // stack: [&result[index], obj] il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] context.LoadObj(); // stack: [obj] var count = il.DeclareLocal(typeof(int)); il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetLastIndexFieldNames)); // stack: [obj.m_lastIndex] il.Dup(); il.Stloc(count); // count = obj.m_lastIndex; stack: [] var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Brfalse(writeDataLengthLabel); context.LoadObj(); // stack: [obj] var slotType = Type.GetNestedType("Slot", 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: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(slots); // stack: [slots] il.Ldloc(i); // stack: [slots, i] il.Ldelema(slotType); // stack: [&slots[i]] il.Dup(); // stack: [&slots[i], &slots[i]] var slot = il.DeclareLocal(slotType.MakeByRefType()); il.Stloc(slot); // slot = &slots[i]; stack: [slot] il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.hashCode] il.Ldc_I4(0); // stack: [slot.hashCode, 0] var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [] il.Ldloc(slot); // stack: [slot] il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.value] il.Ldc_I4(1); // stack: [obj[i], true] context.LoadResult(); // stack: [obj[i], true, result] context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] context.LoadContext(); // stack: [obj[i], true, result, ref index, context] context.CallWriter(elementType); // write<elementType>(obj[i], true, result, ref index, context) il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [count] il.Ldloc(i); // stack: [count, i] il.Ldc_I4(1); // stack: [count, i, 1] il.Add(); // stack: [count, i + 1] il.Dup(); // stack: [count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] context.LoadIndex(); // stack: [result + start, index] il.Ldloc(start); // stack: [result + start, index, start] il.Sub(); // stack: [result + start, index - start] il.Ldc_I4(4); // stack: [result + start, index - start, 4] il.Sub(); // stack: [result + start, index - start - 4] il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [obj] il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] CountArraySize(elementType, il); // stack: [obj size] il.Stloc(size); // size = obj size; stack: [] context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(size); // stack: [&result[index], size] il.Stind(typeof(int)); // result[index] = size; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(size); context.AssertLength(); context.LoadObj(); // stack: [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); context.LoadObj(); // stack: [obj] il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetCountFieldNames)); // stack: [obj.m_lastIndex] il.Dup(); var count = context.LocalInt; il.Stloc(count); // count = obj.m_lastIndex; stack: [count] var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Brfalse(writeDataLengthLabel); var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] context.GoToCurrentLocation(); // stack: [&result[index]] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(slots); // stack: [current, slots] il.Ldloc(i); // stack: [current, slots, i] il.Ldelema(slotType); // stack: [current, &slots[i]] il.Dup(); // stack: [current, &slots[i], &slots[i]] var slot = il.DeclareLocal(slotType.MakeByRefType()); il.Stloc(slot); // slot = &slots[i]; stack: [current, slot] if (PlatformHelpers.IsDotNet50OrGreater) { il.Ldfld(slotType.GetField("Next")); // stack: [current, slot.Next] il.Ldc_I4(-1); // stack: [current, slot.Next, -1] } else { il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, slot.hashCode] il.Ldc_I4(0); // stack: [current, slot.hashCode, 0] } var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [current] il.Dup(); // stack: [current, current] il.Ldloc(slot); // stack: [current, current, slot] il.Ldfld(slotType.GetField(PlatformHelpers.HashSetSlotValueFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); // stack: [current, current, slot.value] il.Stind(elementType); // *current = slot.value; stack: [current] LoadItemSize(elementType, il); // stack: [current, item size] il.Add(); // stack: [current + item size] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [current, count] il.Ldloc(i); // stack: [current, count, i] il.Ldc_I4(1); // stack: [current, count, i, 1] il.Add(); // stack: [current, count, i + 1] il.Dup(); // stack: [current, count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [current, count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] il.Pop(); // stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Dictionary); context.LoadIndex(); // stack: [index] var start = context.LocalInt; il.Stloc(start); // start = index il.Ldc_I4(8); // data length + dict size = 8 context.AssertLength(); context.IncreaseIndexBy4(); // index = index + 4 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObj(); // stack: [&result[index], obj] il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashtableCountFieldNames)); // stack: [&result[index], obj.Count] il.Dup(); var count = il.DeclareLocal(typeof(int)); il.Stloc(count); // count = obj.Count; stack: [&result[index], obj.Count] il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Ldloc(count); // stack: [count] il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] context.LoadObj(); // stack: [obj] var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); var buckets = il.DeclareLocal(bucketType.MakeArrayType()); var bucketsField = Type.GetPrivateInstanceField(PlatformHelpers.HashtableBucketsFieldNames); il.Ldfld(bucketsField); // stack: [obj.buckets] il.Stloc(buckets); // buckets = obj.buckets; stack: [] il.Ldloc(buckets); // stack: [buckets] il.Ldlen(); // stack: [buckets.Length] il.Stloc(count); // count = buckets.Length; stack: [] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(buckets); // stack: [buckets] il.Ldloc(i); // stack: [buckets, i] il.Ldelema(bucketType); // stack: [&buckets[i]] il.Dup(); // stack: [&buckets[i], &buckets[i]] var bucket = il.DeclareLocal(bucketType.MakeByRefType()); il.Stloc(bucket); // bucket = &buckets[i]; stack: [bucket] il.Ldfld(bucketType.GetField("key")); // stack: [bucket.key] il.Dup(); // stack: [bucket.key, bucket.key] var key = il.DeclareLocal(typeof(object)); il.Stloc(key); // key = bucket.key; stack: [key] var nextLabel = il.DefineLabel("next"); il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [] il.Ldloc(key); // stack: [key] context.LoadObj(); // stack: [key, obj] il.Ldfld(bucketsField); // stack: [key, obj.buckets] il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [] il.Ldloc(key); // stack: [obj[i].key] il.Ldc_I4(1); // stack: [obj[i].key, true] context.LoadResult(); // stack: [obj[i].key, true, result] context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] context.CallWriter(typeof(object)); // write<object>(obj[i].key, true, result, ref index, context); stack: [] il.Ldloc(bucket); // stack: [bucket] il.Ldfld(bucketType.GetField("val")); // stack: [bucket.val] il.Ldc_I4(1); // stack: [obj[i].value, true] context.LoadResult(); // stack: [obj[i].value, true, result] context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] context.CallWriter(typeof(object)); // writer<object>(obj[i].value, true, result, ref index, context); stack: [] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [ count] il.Ldloc(i); // stack: [count, i] il.Ldc_I4(1); // stack: [count, i, 1] il.Add(); // stack: [count, i + 1] il.Dup(); // stack: [count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] context.LoadIndex(); // stack: [result + start, index] il.Ldloc(start); // stack: [result + start, index, start] il.Sub(); // stack: [result + start, index - start] il.Ldc_I4(4); // stack: [result + start, index - start, 4] il.Sub(); // stack: [result + start, index - start - 4] il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 }
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); }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; var writers = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair <Delegate, IntPtr>(null, IntPtr.Zero) : GetWriter(context, type1)).ToArray(); var writersField = context.Context.InitConstField(Type, 0, writers.Select(pair => pair.Value).ToArray()); context.Context.InitConstField(Type, 1, writers.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(writers.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.LoadResult(); // stack: [obj, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] il.Ldloc(index); // stack: [obj, writeEmpty, result, ref index, context, writers, index] il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index]] var parameterTypes = new[] { typeof(object), typeof(bool), typeof(byte *), typeof(int).MakeByRefType(), typeof(WriterContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index](obj, writeEmpty, result, ref index, context)] il.Ret(); il.MarkLabel(tryAsArrayLabel); il.Ldloc(type); // stack: [obj.GetType()] il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray] var writeNullLabel = il.DefineLabel("writeNull"); il.Brfalse(writeNullLabel); context.LoadObj(); // stack: [obj] context.LoadWriteEmpty(); // stack: [obj, writeEmpty] context.LoadResult(); // stack: [obj, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, result, ref index, context, writers, index of typeof(object[])] il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index of typeof(object[])]] parameterTypes = new[] { typeof(object), typeof(bool), typeof(byte *), typeof(int).MakeByRefType(), typeof(WriterContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index of typeof(object[])](obj, writeEmpty, result, ref index, context)] il.Ret(); il.MarkLabel(writeNullLabel); context.WriteNull(); }
protected abstract void WriteNotEmpty(WriterMethodBuilderContext context);
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); var il = context.Il; var length = context.LocalInt; var start = il.DeclareLocal(typeof(int)); context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Dup(); // stack: [ref index, index, index] il.Stloc(start); // start = index; stack: [ref index, index] il.Ldc_I4(5); // stack: [ref index, index, 5] il.Add(); // stack: [ref index, index + 5] il.Stind(typeof(int)); // index = index + 5; stack: [] 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.LoadResult(); // stack: [customSerializer, (object)obj, writeEmpty, result] context.LoadIndexByRef(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index] context.LoadContext(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index, context] int dummy = 0; var writeMethod = HackHelpers.GetMethodDefinition <IGroBufCustomSerializer>(serializer => serializer.Write(null, false, IntPtr.Zero, ref dummy, null)); il.Call(writeMethod); // customSerializer.Write((object)obj, writeEmpty, result, ref index, context); stack: [] context.LoadIndex(); // stack: [index] il.Ldloc(start); // stack: [index, start] il.Sub(); // stack: [index - start] il.Ldc_I4(5); // stack: [index - start, 5] il.Sub(); // stack: [index - start - 5] var writeLengthLabel = il.DefineLabel("writeLength"); var doneLabel = il.DefineLabel("done"); il.Dup(); // stack: [index - start - 5, index - start - 5] il.Stloc(length); // length = index - start - 5; stack: [length] il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; context.LoadIndexByRef(); // stack: [ref index] il.Ldloc(start); // stack: [ref index, start] il.Stind(typeof(int)); // index = start context.WriteNull(); il.MarkLabel(writeLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] il.Dup(); // stack: [result + start, result + start] il.Ldc_I4((int)GroBufTypeCode.CustomData); // stack: [result + start, result + start, TypeCode.Object] il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] il.Ldc_I4(1); // stack: [result + start, 1] il.Add(); // stack: [result + start + 1] il.Ldloc(length); // stack: [result + start + 1, length] il.Stind(typeof(int)); // *(int*)(result + start + 1) = length il.MarkLabel(doneLabel); }
protected override void WriteNotEmpty(WriterMethodBuilderContext 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 writeUsual = il.DefineLabel("writeUsual"); il.Brfalse(writeUsual); // if(factory == null) goto writeUsual; stack: [] il.Ldloc(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(writeUsual); // if(!(rawData is RawData)) goto writeUsual; 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(writeUsual); // if(rawData.serializerId != context.serializerId) goto writeUsual; stack: [] var data = il.DeclareLocal(typeof(byte).MakeByRefType(), true); var length = il.DeclareLocal(typeof(int)); il.Ldloc(rawData); // stack: [rawData] il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] il.Dup(); // stack: [rawData.data, rawData.data] il.Ldlen(); // stack: [rawData.data, rawData.data.Length] il.Stloc(length); // length = rawData.data.Length; stack: [rawData.data] il.Ldc_I4(0); // stack: [rawData.data, 0] il.Ldelema(typeof(byte)); // stack: [&rawData.data[0]] il.Stloc(data); // data = &rawData.data; stack: [] il.Ldloc(length); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(data); // stack: [&result[index], data] il.Ldloc(length); // stack: [&result[index], data, data.Length] il.Cpblk(); // result[index] = data; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(length); // stack: [ref index, index, data.Length] il.Add(); // stack: [ref index, index + data.Length] il.Stind(typeof(int)); // index = index + data.Length; stack: [] il.FreePinnedLocal(data); // data = null; stack: [] il.Ret(); il.MarkLabel(writeUsual); context.LoadObj(); // stack: [obj] il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] context.LoadResult(); // stack: [obj.Value, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj.Value, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj.Value, writeEmpty, result, ref index, context] context.CallWriter(argument); // writer(obj.Value, writeEmpty, result, ref index, context) }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCode.Array); var length = il.DeclareLocal(typeof(int)); context.LoadObjByRef(); // stack: [ref obj] il.Ldfld(countField); // stack: [obj._count] il.Stloc(length); // length = obj._count context.LoadIndex(); // stack: [index] var start = context.LocalInt; il.Stloc(start); // start = index il.Ldc_I4(8); context.AssertLength(); // 8 = data size + array length context.IncreaseIndexBy4(); // index = index + 4 context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(length); // stack: [&result[index], length] il.Stind(typeof(int)); // *(int*)&result[index] = length; stack: [] context.IncreaseIndexBy4(); // index = index + 4 var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Ldloc(length); // stack: [length] il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] var i = il.DeclareLocal(typeof(int)); context.LoadObjByRef(); // stack: [ref obj] il.Ldfld(offsetField); // stack: [obj._offset] il.Dup(); // stack: [obj._offset, obj._offset] il.Stloc(i); // i = obj._offset; stack: [obj._offset] il.Ldloc(length); // stack: [obj._offset, length] il.Add(); // stack: [obj._offset + length] il.Stloc(length); // length = obj._offset + length; stack: [] var array = il.DeclareLocal(elementType.MakeArrayType()); context.LoadObjByRef(); // stack: [ref obj] il.Ldfld(arrayField); // stack: [obj._array] il.Stloc(array); // array = obj._array; stack: [] var cycleStart = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStart); il.Ldloc(array); // stack: [array] il.Ldloc(i); // stack: [array, i] il.Ldelem(elementType); il.Ldc_I4(1); // stack: [array[i], true] context.LoadResult(); // stack: [array[i], true, result] context.LoadIndexByRef(); // stack: [array[i], true, result, ref index] context.LoadContext(); // stack: [array[i], true, result, ref index, context] context.CallWriter(elementType); // writer(array[i], true, result, ref index, context); stack: [] il.Ldloc(length); // stack: [length] il.Ldloc(i); // stack: [length, i] il.Ldc_I4(1); // stack: [length, i, 1] il.Add(); // stack: [length, i + 1] il.Dup(); // stack: [length, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [length, i] il.Bgt(cycleStart, false); // if(length > i) goto cycleStart; stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] context.LoadIndex(); // stack: [result + start, index] il.Ldloc(start); // stack: [result + start, index, start] il.Sub(); // stack: [result + start, index - start] il.Ldc_I4(4); // stack: [result + start, index - start, 4] il.Sub(); // stack: [result + start, index - start - 4] il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; var length = context.LocalInt; var start = il.DeclareLocal(typeof(int)); context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Dup(); // stack: [ref index, index, index] il.Stloc(start); // start = index; stack: [ref index, index] il.Ldc_I4(5); // stack: [ref index, index, 5] il.Add(); // stack: [ref index, index + 5] il.Stind(typeof(int)); // index = index + 5; stack: [] var dataMembers = context.Context.GetDataMembers(Type); var hashCodes = GroBufHelpers.CalcHashesAndCheck(dataMembers); var prev = il.DeclareLocal(typeof(int)); for (var i = 0; i < dataMembers.Length; i++) { var member = dataMembers[i]; if (Type.IsValueType) { context.LoadObjByRef(); // stack: [ref obj] } else { context.LoadObj(); // stack: [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: [obj.prop] memberType = property.PropertyType; break; case MemberTypes.Field: var field = (FieldInfo)member.Member; il.Ldfld(field); // stack: [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: [obj.prop, false] context.LoadResult(); // stack: [obj.prop, false, result] context.LoadIndexByRef(); // stack: [obj.prop, false, result, ref index] il.Dup(); // stack: [obj.prop, false, result, ref index, ref index] context.LoadIndex(); // stack: [obj.prop, false, result, ref index, ref index, index] il.Dup(); // stack: [obj.prop, false, result, ref index, ref index, index, index] il.Stloc(prev); // prev = index; stack: [obj.prop, false, result, ref index, ref index, index] il.Ldc_I4(8); // stack: [obj.prop, false, result, ref index, ref index, index, 8] il.Add(); // stack: [obj.prop, false, result, ref index, ref index, index + 8] il.Stind(typeof(int)); // index = index + 8; stack: [obj.prop, false, result, ref index] context.LoadContext(); // stack: [obj.prop, false, result, ref index, context] context.CallWriter(memberType); // writers[i](obj.prop, false, result, ref index, ref result, context) context.LoadIndex(); // stack: [index] il.Ldc_I4(8); // stack: [index, 8] il.Sub(); // stack: [index - 8] il.Ldloc(prev); // stack: [index - 8, prev] var writeHashCodeLabel = il.DefineLabel("writeHashCode"); il.Bgt(writeHashCodeLabel, false); // if(index - 8 > prev) goto writeHashCode; context.LoadIndexByRef(); // stack: [ref index] il.Ldloc(prev); // stack: [ref index, prev] il.Stind(typeof(int)); // index = prev; var nextLabel = il.DefineLabel("next"); il.Br(nextLabel); // goto next; il.MarkLabel(writeHashCodeLabel); context.LoadResult(); // stack: [result] il.Ldloc(prev); // stack: [result, prev] il.Add(); // stack: [result + prev] il.Ldc_I8((long)hashCodes[i]); // stack: [&result[index], prop.Name.HashCode] il.Stind(typeof(long)); // *(long*)(result + prev) = prop.Name.HashCode; stack: [] il.MarkLabel(nextLabel); } context.LoadIndex(); // stack: [index] il.Ldloc(start); // stack: [index, start] il.Sub(); // stack: [index - start] il.Ldc_I4(5); // stack: [index - start, 5] il.Sub(); // stack: [index - start - 5] il.Stloc(length); // length = index - start - 5; stack: [] if (!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) { var writeLengthLabel = il.DefineLabel("writeLength"); il.Ldloc(length); // stack: [length] il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; context.LoadIndexByRef(); // stack: [ref index] il.Ldloc(start); // stack: [ref index, start] il.Stind(typeof(int)); // index = start context.WriteNull(); il.MarkLabel(writeLengthLabel); } context.LoadResult(); // stack: [result] il.Ldloc(start); // stack: [result, start] il.Add(); // stack: [result + start] il.Dup(); // stack: [result + start, result + start] il.Ldc_I4((int)GroBufTypeCode.Object); // stack: [result + start, result + start, TypeCode.Object] il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] il.Ldc_I4(1); // stack: [result + start, 1] il.Add(); // stack: [result + start + 1] il.Ldloc(length); // stack: [result + start + 1, length] il.Stind(typeof(int)); // *(int*)(result + start + 1) = length }