예제 #1
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            int[]   values;
            ulong[] hashCodes;
            EnumHelpers.BuildValuesTable(Type, out values, out hashCodes);
            var valuesField    = context.Context.InitConstField(Type, 0, values);
            var hashCodesField = context.Context.InitConstField(Type, 1, hashCodes);
            var il             = context.Il;

            il.Ldloc(context.TypeCode); // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.Enum);
            var tryParseLabel = il.DefineLabel("tryParse");

            il.Bne_Un(tryParseLabel);      // if(typeCode != GroBufTypeCode.Enum) goto tryParse;
            context.IncreaseIndexBy1();
            il.Ldc_I4(8);                  // stack: [8]
            context.AssertLength();
            context.LoadResultByRef();     // stack: [ref result]
            context.GoToCurrentLocation(); // stack: [ref result, &result[index]]
            il.Ldind(typeof(long));        // stack: [ref result, *(int64*)result[index] = hashCode]
            context.IncreaseIndexBy8();    // index = index + 8; stack: [ref result, hashCode]

            var parseByHashCodeLabel = il.DefineLabel("parseByHashCode");

            il.MarkLabel(parseByHashCodeLabel);

            il.Dup();                    // stack: [ref result, hashCode, hashCode]
            il.Ldc_I8(hashCodes.Length); // stack: [ref result, hashCode, hashCode, (int64)hashCodes.Length]
            il.Rem(true);                // stack: [ref result, hashCode, hashCode % hashCodes.Length = idx]
            il.Conv <int>();             // stack: [ref result, hashCode, (int)(hashCode % hashCodes.Length)]
            var idx = context.Length;

            il.Stloc(idx);                     // idx = (int)(hashCode % hashCodes.Length); stack: [ref result, hashCode]

            context.LoadField(hashCodesField); // stack: [ref result, hashCode, hashCodes]
            il.Ldloc(idx);                     // stack: [ref result, hashCode, hashCodes, idx]
            il.Ldelem(typeof(long));           // stack: [ref result, hashCode, hashCodes[idx]]
            var returnDefaultLabel = il.DefineLabel("returnDefault");

            il.Bne_Un(returnDefaultLabel);  // if(hashCode != hashCodes[idx]) goto returnDefault; stack: [ref result]
            context.LoadField(valuesField); // stack: [ref result, values]
            il.Ldloc(idx);                  // stack: [ref result, values, idx]
            il.Ldelem(typeof(int));         // stack: [ref result, values[idx]]
            il.Stind(typeof(int));          // result = values[idx]; stack: []
            il.Ret();
            il.MarkLabel(returnDefaultLabel);
            il.Ldc_I4(0);          // stack: [0]
            il.Stind(typeof(int)); // result = 0
            il.Ret();

            il.MarkLabel(tryParseLabel);
            il.Ldloc(context.TypeCode);            // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.String); // stack: [typeCode, GroBufTypeCode.String]
            var readAsIntLabel = il.DefineLabel("readAsInt");

            il.Bne_Un(readAsIntLabel); // if(typeCode != GroBufTypeCode.String) goto readAsInt;
            var str = il.DeclareLocal(typeof(string));

            context.LoadData();                                                                              // stack: [pinnedData]
            context.LoadIndexByRef();                                                                        // stack: [pinnedData, ref index]
            il.Ldloca(str);                                                                                  // stack: [pinnedData, ref index, ref str]
            context.LoadContext();                                                                           // stack: [pinnedData, ref index, ref str, context]
            context.CallReader(typeof(string));                                                              // reader<string>(pinnedData, ref index, ref str, context); stack: []
            context.LoadResultByRef();                                                                       // stack: [ref result]
            il.Ldloc(str);                                                                                   // stack: [ref result, str]
            il.Call(typeof(GroBufHelpers).GetMethod("CalcHash", BindingFlags.Public | BindingFlags.Static)); // stack: [ref result, GroBufHelpers.CalcHash(str)]
            il.Br(parseByHashCodeLabel);

            il.MarkLabel(readAsIntLabel);

            context.LoadData();              // stack: [pinnedData]
            context.LoadIndexByRef();        // stack: [pinnedData, ref index]
            context.LoadResultByRef();       // stack: [pinnedData, ref index, ref result]
            context.LoadContext();           // stack: [pinnedData, ref index, ref result, context]
            context.CallReader(typeof(int)); // reader<int>(pinnedData, ref index, ref result, context)
        }