Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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();
        }
Ejemplo n.º 4
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
        }