protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); context.WriteTypeCode(typeCode); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], ref obj] il.Ldfld(countField); // stack: [&result[index], obj._count] CountArraySize(elementType, il); // stack: [&result[index], obj size] il.Dup(); // stack: [&result[index], obj size, obj size] il.Stloc(size); // size = obj size; stack: [&result[index], obj size] il.Stind(typeof(int)); // result[index] = size; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] var doneLabel = il.DefineLabel("done"); il.Ldloc(size); // stack: [size] il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] il.Ldloc(size); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], ref obj] il.Ldfld(arrayField); // stack: [&result[index], obj._array] context.LoadObjByRef(); // stack: [&result[index], obj._array, ref obj] il.Ldfld(offsetField); // stack: [&result[index], obj._array, obj._offset] il.Ldelema(elementType); // stack: [&result[index], &obj._array[obj._offset]] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); il.Stloc(arr); // arr = &obj._array[obj._offset]; stack: [&result[index]] il.Ldloc(arr); // stack: [&result[index], arr] il.Ldloc(size); // stack: [&result[index], arr + obj._offset, size] il.Cpblk(); // &result[index] = arr il.FreePinnedLocal(arr); // arr = null; stack: [] 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 il.MarkLabel(doneLabel); }
protected override bool CheckEmpty(WriterMethodBuilderContext 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 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 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.LoadObjByRef(); // stack: [obj] il.Ldfld(Type.GetField("_ticks", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._ticks] context.LoadWriteEmpty(); // stack: [obj._ticks, writeEmpty] context.LoadResult(); // stack: [obj._ticks, writeEmpty, result] context.LoadIndexByRef(); // stack: [obj._ticks, writeEmpty, result, ref index] context.LoadContext(); // stack: [obj._ticks, writeEmpty, result, ref index, context] context.CallWriter(typeof(long)); // writer(obj._ticks, 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.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.LoadObjByRef(); // stack: [&obj] il.Call(Type.GetProperty("Value").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(Type.GetGenericArguments()[0]); // writer(obj.Value, 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.DateTimeNew); il.Ldc_I4(8); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], &obj] il.Call(dateTimeToBinaryMethod, Type); // stack: [&result[index], obj.ToBinary()] il.Stind(typeof(long)); // result[index] = obj.ToBinary() context.IncreaseIndexBy8(); // index = index + 8 }
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 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; 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 }