コード例 #1
0
        private static KeyValuePair <Delegate, IntPtr> GetReader(ReaderMethodBuilderContext context, Type type)
        {
            var method = new DynamicMethod("Read_" + type.Name + "_AndCastToObject_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)
            }, context.Context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(2);      // stack: [ref result]
                il.Ldarg(0);      // stack: [ref result, data]
                il.Ldarg(1);      // stack: [ref result, data, ref index]
                var value = il.DeclareLocal(type);
                il.Ldloca(value); // stack: [ref result, data, ref index, ref value]
                il.Ldarg(3);      // stack: [ref result, data, ref index, ref value, context]

                ReaderMethodBuilderContext.CallReader(il, type, context.Context);

                il.Ldloc(value); // stack: [ref result, value]
                if (type.IsValueType)
                {
                    il.Box(type); // stack: [ref result, (object)value]
                }
                else
                {
                    il.Castclass(type);
                }
                il.Stind(typeof(object)); // result = (object)value
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
コード例 #2
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)));
        }
コード例 #3
0
        public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext)
        {
            var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] { Type, typeof(bool), typeof(WriterContext) }, sizeCounterBuilderContext.Module, true);

            sizeCounterBuilderContext.SetSizeCounterMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new SizeCounterMethodBuilderContext(sizeCounterBuilderContext, il);

                var notEmptyLabel = il.DefineLabel("notEmpty");
                if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty
                {
                    context.ReturnForNull();            // return for null
                }
                il.MarkLabel(notEmptyLabel);            // Now we know that obj is not empty

                if (!Type.IsValueType && IsReference && sizeCounterBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences))
                {
                    // Pack reference
                    var index = il.DeclareLocal(typeof(int));
                    context.LoadContext();                                                                                // stack: [context]
                    il.Dup();                                                                                             // stack: [context, context]
                    il.Ldfld(WriterContext.IndexField);                                                                   // stack: [context, context.index]
                    il.Stloc(index);                                                                                      // index = context.index; stack: [context]
                    il.Ldfld(WriterContext.ObjectsField);                                                                 // stack: [context.objects]
                    context.LoadObj();                                                                                    // stack: [context.objects, obj]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.ContainsKey(null))); // stack: [context.object.ContainsKey(obj)]
                    var storeLocationLabel = il.DefineLabel("storeLocation");
                    il.Brfalse(storeLocationLabel);                                                                       // if(!context.objects.ContainsKey(obj)) goto storeLocation; stack: []
                    context.LoadContext();                                                                                // stack: [context]
                    il.Dup();                                                                                             // stack: [context, context]
                    il.Ldfld(WriterContext.ReferencesField);                                                              // stack: [context, context.references]
                    il.Ldc_I4(1);                                                                                         // stack: [context, context.references, 1]
                    il.Add();                                                                                             // stack: [context, context.references + 1]
                    il.Stfld(WriterContext.ReferencesField);                                                              // context.references += 1; stack: []
                    il.Ldc_I4(5);                                                                                         // stack: [5]
                    il.Ret();                                                                                             // return 5
                    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);
                }

                CountSizeNotEmpty(context); // Count size
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate);
        }
コード例 #4
0
        // todo: kill
        private KeyValuePair <Delegate, IntPtr> BuildDefaultValueReader(ModuleBuilder module)
        {
            var method = new DynamicMethod("Default_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(1);      // stack: [ref result]
                il.Initobj(Type); // [result = default(T)]
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
コード例 #5
0
        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;
            }
        }
コード例 #6
0
 private void Zzz()
 {
     try
     {
         for (int i = 1; i < 1000; ++i)
         {
             GroBufHelpers.CalcHash(new string('z', i));
         }
     }
     catch (Exception e)
     {
         Console.WriteLine(e.ToString());
         wasBug = true;
     }
 }
コード例 #7
0
        private KeyValuePair <Delegate, IntPtr> BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode)
        {
            var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true);

            using (var il = new GroboIL(method))
            {
                var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type);

                il.Ldarg(1); // stack: [ref result]
                if (typeCode == GroBufTypeCode.Decimal)
                {
                    if (expectedTypeCode == GroBufTypeCode.Boolean)
                    {
                        il.Ldarg(0);            // stack: [ref result, &temp, address]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address]
                        il.Ldarg(0);            // stack: [ref result, &temp + 8, address]
                        il.Ldc_I4(8);           // stack: [ref result, &temp + 8, address, 8]
                        il.Add();               // stack: [ref result, &temp + 8, address + 8]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)]
                        il.Or();
                        il.Ldc_I4(0);           // stack: [ref result, value, 0]
                        il.Conv <long>();
                        il.Ceq();               // stack: [ref result, value == 0]
                        il.Ldc_I4(1);           // stack: [ref result, value == 0, 1]
                        il.Xor();               // stack: [ref result, value != 0]
                    }
                    else
                    {
                        var temp = il.DeclareLocal(typeof(decimal));
                        il.Ldloca(temp);        // stack: [ref result, &temp]
                        il.Ldarg(0);            // stack: [ref result, &temp, address]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address]
                        il.Stind(typeof(long)); // *temp = *address;
                        il.Ldloca(temp);        // stack: [ref result, &temp]
                        il.Ldc_I4(8);           // stack: [ref result, &temp, 8]
                        il.Add();               // stack: [ref result, &temp + 8]
                        il.Ldarg(0);            // stack: [ref result, &temp + 8, address]
                        il.Ldc_I4(8);           // stack: [ref result, &temp + 8, address, 8]
                        il.Add();               // stack: [ref result, &temp + 8, address + 8]
                        il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)]
                        il.Stind(typeof(long)); // *(temp + 8) = *(address + 8);

                        il.Ldloc(temp);         // stack: [ref result, ref temp]
                        switch (expectedTypeCode)
                        {
                        case GroBufTypeCode.Int8:
                            il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp]
                            break;

                        case GroBufTypeCode.UInt8:
                            il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp]
                            break;

                        case GroBufTypeCode.Int16:
                            il.Call(decimalToInt16Method); // stack: [ref result, (short)temp]
                            break;

                        case GroBufTypeCode.UInt16:
                            il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp]
                            break;

                        case GroBufTypeCode.Int32:
                            il.Call(decimalToInt32Method); // stack: [ref result, (int)temp]
                            break;

                        case GroBufTypeCode.UInt32:
                            il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp]
                            break;

                        case GroBufTypeCode.Int64:
                            il.Call(decimalToInt64Method); // stack: [ref result, (long)temp]
                            break;

                        case GroBufTypeCode.UInt64:
                            il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp]
                            break;

                        case GroBufTypeCode.Single:
                            il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp]
                            break;

                        case GroBufTypeCode.Double:
                            il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp]
                            break;

                        case GroBufTypeCode.Decimal:
                            break;

                        default:
                            throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported");
                        }
                    }
                }
                else
                {
                    il.Ldarg(0);                                                                                // stack: [ref result, address]
                    EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value]
                    if (Type == typeof(bool))
                    {
                        il.Conv <long>();
                        il.Ldc_I4(0); // stack: [ref result, value, 0]
                        il.Conv <long>();
                        il.Ceq();     // stack: [ref result, value == 0]
                        il.Ldc_I4(1); // stack: [ref result, value == 0, 1]
                        il.Xor();     // stack: [ref result, value != 0]
                    }
                    else
                    {
                        EmitConvertValue(il, typeCode, expectedTypeCode);
                    }
                }
                switch (expectedTypeCode)
                {
                case GroBufTypeCode.Int8:
                case GroBufTypeCode.UInt8:
                case GroBufTypeCode.Boolean:
                    il.Stind(typeof(byte)); // result = value
                    break;

                case GroBufTypeCode.Int16:
                case GroBufTypeCode.UInt16:
                    il.Stind(typeof(short)); // result = value
                    break;

                case GroBufTypeCode.Int32:
                case GroBufTypeCode.UInt32:
                    il.Stind(typeof(int)); // result = value
                    break;

                case GroBufTypeCode.Int64:
                case GroBufTypeCode.UInt64:
                    il.Stind(typeof(long)); // result = value
                    break;

                case GroBufTypeCode.Single:
                    il.Stind(typeof(float)); // result = value
                    break;

                case GroBufTypeCode.Double:
                    il.Stind(typeof(double)); // result = value
                    break;

                case GroBufTypeCode.Decimal:
                    il.Stobj(typeof(decimal)); // result = value
                    break;

                default:
                    throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported");
                }
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
コード例 #8
0
        private KeyValuePair <Delegate, IntPtr> GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member)
        {
            var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [data]
                il.Ldarg(1); // stack: [data, ref index]
                switch (member.MemberType)
                {
                case MemberTypes.Field:
                    var field = (FieldInfo)member;
                    var done  = false;
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType)
                    {
                        var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (field.FieldType.IsPrimitive || equalityOperator != null)
                        {
                            var fieldValue = il.DeclareLocal(field.FieldType);
                            il.Ldarg(2); // stack: [data, ref index, ref result]
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldfld(field);
                            il.Stloc(fieldValue);
                            il.Ldloca(fieldValue);
                            il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                            ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []

                            var temp = il.DeclareLocal(field.FieldType);
                            il.Ldloca(temp);
                            il.Initobj(field.FieldType);
                            il.Ldloc(temp);
                            il.Ldloc(fieldValue);
                            if (field.FieldType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                            il.Ldarg(2);
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldloc(fieldValue);
                            il.Stfld(field);
                            done = true;
                        }
                    }
                    if (!done)
                    {
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                  // stack: [data, ref index, result]
                        }
                        il.Ldflda(field);                                                    // stack: [data, ref index, ref result.field]
                        il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                        ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []
                    }
                    break;

                case MemberTypes.Property:
                    var property      = (PropertyInfo)member;
                    var propertyValue = il.DeclareLocal(property.PropertyType);
                    if (context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead))
                    {
                        var getter = property.GetGetMethod(true);
                        if (getter == null)
                        {
                            throw new MissingMethodException(Type.Name, property.Name + "_get");
                        }
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                    // stack: [data, ref index, result]
                        }
                        il.Call(getter, Type);                                                 // stack: [ data, ref index, result.property]
                        il.Stloc(propertyValue);                                               // propertyValue = result.property; stack: [data, ref index]
                    }
                    il.Ldloca(propertyValue);                                                  // stack: [data, ref index, ref propertyValue]
                    il.Ldarg(3);                                                               // stack: [data, ref index, ref propertyValue, context]
                    ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: []
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType)
                    {
                        var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (property.PropertyType.IsPrimitive || equalityOperator != null)
                        {
                            var temp = il.DeclareLocal(property.PropertyType);
                            il.Ldloca(temp);
                            il.Initobj(property.PropertyType);
                            il.Ldloc(temp);
                            il.Ldloc(propertyValue);
                            if (property.PropertyType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                        }
                    }
                    il.Ldarg(2); // stack: [ref result]
                    if (!Type.IsValueType)
                    {
                        il.Ldind(Type);      // stack: [result]
                    }
                    il.Ldloc(propertyValue); // stack: [result, propertyValue]
                    var setter = property.GetSetMethod(true);
                    if (setter == null)
                    {
                        throw new MissingMethodException(Type.Name, property.Name + "_set");
                    }
                    il.Call(setter, Type); // result.property = propertyValue
                    break;

                default:
                    throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported");
                }
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
コード例 #9
0
        public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext)
        {
            var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, readerTypeBuilderContext.Module, true);

            readerTypeBuilderContext.SetReaderMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference);

                ReadTypeCodeAndCheck(context); // Read TypeCode and check

                if (!Type.IsValueType && IsReference)
                {
                    // Read reference
                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    var notReadLabel = il.DefineLabel("notRead");
                    il.Brfalse(notReadLabel);
                    context.LoadIndex();                  // stack: [external index]
                    context.LoadContext();                // stack: [external index, context]
                    il.Ldfld(ReaderContext.StartField);   // stack: [external index, context.start]
                    il.Sub();                             // stack: [external index - context.start]
                    il.Stloc(context.Index);              // index = external index - context.start; stack: []

                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    il.Ldloc(context.Index);              // stack: [context.objects, index]
                    var obj = il.DeclareLocal(typeof(object));
                    il.Ldloca(obj);
                    object dummy;
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)]
                    il.Brfalse(notReadLabel);                                                                                     // if(!context.objects.TryGetValue(index, out obj)) goto notRead;
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    context.IncreaseIndexBy1();                                                                                   // Skip type code
                    context.SkipValue();                                                                                          // Skip value - it has already been read
                    il.Ret();
                    il.MarkLabel(notReadLabel);
                    il.Ldloc(context.TypeCode);               // stack: [typeCode]
                    il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference]
                    var readUsualLabel = il.DefineLabel("readUsual");
                    il.Bne_Un(readUsualLabel);                // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: []

                    context.LoadContext();                    // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);     // stack: [context.objects]
                    var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull");
                    il.Brtrue(objectsIsNotNullLabel);         // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects]
                    il.Ldstr("Reference is not valid at this point");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(objectsIsNotNullLabel);

                    context.IncreaseIndexBy1(); // index = index + 1; stack: []
                    il.Ldc_I4(4);
                    context.AssertLength();
                    context.GoToCurrentLocation();
                    var reference = il.DeclareLocal(typeof(int));
                    il.Ldind(typeof(int));             // stack: [*(int*)data[index]]
                    il.Stloc(reference);               // reference = *(int*)data[index]; stack: []
                    context.IncreaseIndexBy4();        // index = index + 4; stack: []
                    il.Ldloc(context.Index);           // stack: [index]
                    il.Ldloc(reference);               // stack: [index, reference]
                    var goodReferenceLabel = il.DefineLabel("goodReference");
                    il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: []
                    il.Ldstr("Bad reference");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(goodReferenceLabel);
                    context.LoadContext();                                                                                        // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);                                                                         // stack: [context.objects]
                    il.Ldloc(reference);                                                                                          // stack: [context.objects, reference]
                    il.Ldloca(obj);                                                                                               // stack: [context.objects, reference, ref obj]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)]
                    var readObjectLabel = il.DefineLabel("readObject");
                    il.Brfalse(readObjectLabel);                                                                                  // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: []
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    il.Ret();
                    il.MarkLabel(readObjectLabel);

                    // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted
                    context.LoadData();                 // stack: [data]
                    il.Ldloc(reference);                // stack: [data, reference]
                    context.LoadContext();              // stack: [data, reference, context]
                    il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start]
                    il.Add();                           // stack: [data, reference + context.start]
                    il.Stloc(reference);                // reference += context.start; stack: [data]
                    il.Ldloca(reference);               // stack: [data, ref reference]
                    context.LoadResultByRef();          // stack: [data, ref reference, ref result]
                    context.LoadContext();              // stack: [data, ref reference, ref result, context]
                    context.CallReader(Type);
                    il.Ret();
                    il.MarkLabel(readUsualLabel);
                }

                ReadNotEmpty(context); // Read obj
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate);
        }
コード例 #10
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);
        }
コード例 #11
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
        }