private void BuildMembersTable(ReaderTypeBuilderContext context, out ulong[] hashCodes, out MemberInfo[] dataMembers) { var members = context.GetDataMembers(Type); var hashes = GroBufHelpers.CalcHashesAndCheck(members); var n = GroBufHelpers.CalcSize(hashes); hashCodes = new ulong[n]; dataMembers = new MemberInfo[n]; for (var i = 0; i < members.Length; i++) { var index = (int)(hashes[i] % n); hashCodes[index] = hashes[i]; dataMembers[index] = members[i].Member; } }
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 }