Пример #1
0
        private static KeyValuePair <Delegate, IntPtr> GetWriter(WriterMethodBuilderContext context, Type type)
        {
            var method = new DynamicMethod("CastTo_" + type.Name + "_AndWrite_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), 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, result]
                il.Ldarg(3);            // stack: [(type)obj, writeEmpty, result, ref index]
                il.Ldarg(4);            // stack: [(type)obj, writeEmpty, result, ref index, context]
                context.CallWriter(il, type);
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(WriterDelegate <object>));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
Пример #2
0
        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)
        }
Пример #4
0
        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)
        }
Пример #5
0
        protected override void WriteNotEmpty(WriterMethodBuilderContext context)
        {
            var il = context.Il;

            context.LoadObj();                                                                       // stack: [obj]
            il.Call(Type.GetMethod("GetAddressBytes", BindingFlags.Instance | BindingFlags.Public)); // stack: [obj.GetAddressBytes()]
            context.LoadWriteEmpty();                                                                // stack: [obj.GetAddressBytes(), writeEmpty]
            context.LoadResult();                                                                    // stack: [obj.GetAddressBytes(), writeEmpty, result]
            context.LoadIndexByRef();                                                                // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index]
            context.LoadContext();                                                                   // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index, context]
            context.CallWriter(typeof(byte[]));                                                      // writer(obj.GetAddressBytes(), writeEmpty, result, ref index, context)
        }
Пример #6
0
        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)
        }
Пример #7
0
        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: []
        }
Пример #8
0
        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
        }
Пример #9
0
        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
        }
Пример #10
0
        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
        }
Пример #11
0
        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
        }
Пример #12
0
        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)
        }
Пример #13
0
        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
        }
Пример #14
0
        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
        }