Пример #1
0
        private static void EmitReadPrimitiveValue(GroboIL il, GroBufTypeCode typeCode)
        {
            switch (typeCode)
            {
            case GroBufTypeCode.Int8:
                il.Ldind(typeof(sbyte));
                break;

            case GroBufTypeCode.UInt8:
            case GroBufTypeCode.Boolean:
                il.Ldind(typeof(byte));
                break;

            case GroBufTypeCode.Int16:
                il.Ldind(typeof(short));
                break;

            case GroBufTypeCode.UInt16:
                il.Ldind(typeof(ushort));
                break;

            case GroBufTypeCode.Int32:
                il.Ldind(typeof(int));
                break;

            case GroBufTypeCode.UInt32:
                il.Ldind(typeof(uint));
                break;

            case GroBufTypeCode.Int64:
            case GroBufTypeCode.DateTimeNew:
                il.Ldind(typeof(long));
                break;

            case GroBufTypeCode.UInt64:
                il.Ldind(typeof(ulong));
                break;

            case GroBufTypeCode.Single:
                il.Ldind(typeof(float));
                break;

            case GroBufTypeCode.Double:
                il.Ldind(typeof(double));
                break;

            default:
                throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported");
            }
        }
Пример #2
0
        private static Func <IntPtr, long, long> EmitRelJmpHooker()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(long), new[] { typeof(IntPtr), typeof(long) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.VerificationKind = TypesAssignabilityVerificationKind.LowLevelOnly;
                var cycleLabel = il.DefineLabel("cycle");
                il.MarkLabel(cycleLabel);
                il.Ldarg(0);            // stack: [ptr]
                il.Dup();               // stack: [ptr, ptr]
                var x = il.DeclareLocal(typeof(long));
                il.Ldind(typeof(long)); // stack: [ptr, *ptr]
                il.Dup();
                il.Stloc(x);            // x = *ptr; stack: [ptr, newCode]
                il.Ldc_I8(unchecked ((long)0xFFFFFF0000000000));
                il.And();               // stack: [ptr, x & 0xFFFFFF0000000000]
                il.Ldarg(1);            // stack: [ptr, x & 0xFFFFFF0000000000, code]
                il.Or();                // stack: [ptr, (x & 0xFFFFFF0000000000) | code]
                il.Ldloc(x);            // stack: [ptr, (x & 0xFFFFFF0000000000) | code, newCode]
                var methodInfo = typeof(Interlocked).GetMethod("CompareExchange", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(long).MakeByRefType(), typeof(long), typeof(long) }, null);
                il.Call(methodInfo);    // stack: [Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode)]
                il.Ldloc(x);            // stack: [Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode), newCode]
                il.Bne_Un(cycleLabel);  // if(Interlocked.CompareExchange(ptr, (x & 0xFFFFFF0000000000) | code, newCode) != newCode) goto cycle; stack: []
                il.Ldloc(x);
                il.Ret();
            }
            return((Func <IntPtr, long, long>)method.CreateDelegate(typeof(Func <IntPtr, long, long>)));
        }
Пример #3
0
        public void TestPrefixes()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(IntPtr), typeof(int) }, typeof(Test));

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                il.Ldarg(1);
                il.Add();
                il.Ldind(typeof(int));
                il.Ret();
                Console.Write(il.GetILCode());
            }
        }
Пример #4
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)));
        }
Пример #5
0
        private Func <object> BuildConstants(Type type, ClosureSubstituter closureSubstituter)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object[]) },
                                           typeof(ExpressionClosureBuilder), true);
            var root   = Expression.Parameter(type);
            var consts = new object[hashtable.Count];

            using (var il = new GroboIL(method))
            {
                il.Newobj(type.GetConstructor(Type.EmptyTypes)); // stack: [new Constants()]
                var result = il.DeclareLocal(type, "result");
                il.Stloc(result);                                // result = new Constants(); stack: []
                int index = 0;
                foreach (DictionaryEntry entry in hashtable)
                {
                    var pair      = (Tuple <Type, object>)entry.Key;
                    var constType = pair.Item1;
                    consts[index] = pair.Item2 is Expression?closureSubstituter.Visit((Expression)pair.Item2) : pair.Item2;

                    var fieldAccessor = constantsBuilder.MakeAccess(root, ((int?)entry.Value).Value);
                    var pathToField   = new List <FieldInfo>();
                    while (fieldAccessor.NodeType != ExpressionType.Parameter)
                    {
                        var memberExpression = (MemberExpression)fieldAccessor;
                        pathToField.Add((FieldInfo)memberExpression.Member);
                        fieldAccessor = memberExpression.Expression;
                    }
                    pathToField.Reverse();
                    il.Ldloc(result);
                    for (int i = 0; i < pathToField.Count - 1; ++i)
                    {
                        il.Ldflda(pathToField[i]);                            // stack: [ref result.field]
                        il.Dup();                                             // stack: [ref result.field, ref result.field]
                        var fieldType = pathToField[i].FieldType;
                        il.Ldind(fieldType);                                  // stack: [ref result.field, result.field]
                        var notNullLabel = il.DefineLabel("notNull");
                        il.Brtrue(notNullLabel);                              // if(result.field != null) goto notNull; stack: [ref result.field]
                        il.Dup();                                             // stack: [ref result.field, ref result.field]
                        il.Newobj(fieldType.GetConstructor(Type.EmptyTypes)); // stack: [ref result.field, ref result.field, new field()]
                        il.Stind(fieldType);                                  // result.field = new field(); stack: [ref result.field]
                        il.MarkLabel(notNullLabel);
                        il.Ldind(fieldType);                                  // stack: [result.field]
                    }
                    il.Ldarg(0);                                              // stack: [path, args]
                    il.Ldc_I4(index++);                                       // stack: [path, args, index]
                    il.Ldelem(typeof(object));                                // stack: [path, args[index]]
                    var field = pathToField.Last();
                    if (!constType.IsValueType)
                    {
                        il.Castclass(field.FieldType); // stack: [path, (FieldType)args[index]]
                    }
                    else
                    {
                        il.Unbox_Any(constType);
                        if (field.FieldType != constType)
                        {
                            var constructor = field.FieldType.GetConstructor(new[] { constType });
                            if (constructor == null)
                            {
                                throw new InvalidOperationException(string.Format("Missing constructor of type '{0}' with parameter of type '{1}'",
                                                                                  Formatter.Format(field.FieldType), Formatter.Format(constType)));
                            }
                            il.Newobj(constructor);
                        }
                    }
                    il.Stfld(field); // path.field = (FieldType)args[index]; stack: []
                }
                il.Ldloc(result);
                il.Ret();
            }
            var func = (Func <object[], object>)method.CreateDelegate(typeof(Func <object[], object>));

            return(() => func(consts));
        }
Пример #6
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)));
        }
Пример #7
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);
        }
Пример #8
0
        public void TestLocalloc()
        {
            // private static unsafe int GetSum(byte length)
            // {
            //     byte* bytes = stackalloc byte[length];
            //     for (byte i = 0; i < length; ++i)
            //     {
            //         bytes[i] = i;
            //     }
            //     int sum = 0;
            //     for (byte i = 0; i < length; ++i)
            //     {
            //         sum += bytes[i];
            //     }
            //     return sum;
            // }
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(byte) }, typeof(Test));

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);       // stack: [length]
                il.Conv <UIntPtr>();
                il.Localloc();     // stack: [*pointer]
                var pointer = il.DeclareLocal(typeof(UIntPtr));
                il.Stloc(pointer); // pointer = value; stack: []

                il.Ldc_I4(0);      // stack: [0]
                var i = il.DeclareLocal(typeof(byte));
                il.Stloc(i);       // i = 0; stack: []
                var loop1Start = il.DefineLabel("loop1_start");
                var loop1End   = il.DefineLabel("loop1_end");
                il.MarkLabel(loop1Start);
                {
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldarg(0);                      // stack: [i, length]
                    il.Bge(loop1End, unsigned: true); // if (i >= length) goto end; stack: []
                    il.Ldloc(pointer);                //stack: [pointer]
                    il.Ldloc(i);                      // stack: [pointer, i]
                    il.Add();                         // stack: [pointer + i]
                    il.Ldloc(i);                      // stack: [pointer + i, i]
                    il.Stind(typeof(byte));           // *(pointer + i) = i; stack: []
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldc_I4(1);                     // stack: [i, 1]
                    il.Add();                         // stack: [i + 1]
                    il.Conv <byte>();
                    il.Stloc(i);                      // i = i + 1; stack: []
                    il.Br(loop1Start);
                }
                il.MarkLabel(loop1End);

                il.Ldc_I4(0);  // stack: [0]
                il.Dup();      // stack: [0, 0]
                var sum = il.DeclareLocal(typeof(int));
                il.Stloc(sum); // sum = 0; stack: [0]
                il.Stloc(i);   // i = 0; stack: []
                var loop2Start = il.DefineLabel("loop2_start");
                var loop2End   = il.DefineLabel("loop2_end");
                il.MarkLabel(loop2Start);
                {
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldarg(0);                      // stack: [i, length]
                    il.Bge(loop2End, unsigned: true); // if i >= length goto end; stack:[]
                    il.Ldloc(pointer);                // stack: [pointer]
                    il.Ldloc(i);                      // stack: [pointer, i]
                    il.Add();                         // stack: [pointer + i]
                    il.Ldind(typeof(byte));           // stack: [*(pointer + i)]
                    il.Ldloc(sum);                    // stack: [*(pointer + i), sum]
                    il.Add();                         // stack: [*(pointer + i) + sum]
                    il.Stloc(sum);                    // sum = *(pointer + i) + sum; stack: []
                    il.Ldloc(i);                      // stack: [i]
                    il.Ldc_I4(1);                     // stack: [i, 1]
                    il.Add();                         // stack: [i + 1]
                    il.Conv <byte>();
                    il.Stloc(i);                      // i = (i + 1); // stack: []
                    il.Br(loop2Start);
                }
                il.MarkLabel(loop2End);

                il.Ldloc(sum); // stack: [sum]
                il.Ret();
            }
            var func = (Func <byte, int>)method.CreateDelegate(typeof(Func <byte, int>));

            Assert.That(func(6), Is.EqualTo(15));
        }
        public static bool Emit(Expression zarr, Expression zindex, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var arrayType = zarr.Type;
            var isArray   = arrayType.IsArray;

            if (!isArray && !arrayType.IsList())
            {
                throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'");
            }
            var     itemType = isArray ? arrayType.GetElementType() : arrayType.GetGenericArguments()[0];
            GroboIL il       = context.Il;

            EmittingContext.LocalHolder arrayIndex = null;
            bool extendArray        = extend && (CanAssign(zarr) || !isArray);
            bool extendArrayElement = extend && itemType.IsClass;
            var  result             = false;

            if (!extendArray)
            {
                result |= ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.Value, extend, out arrayType); // stack: [array]
                if (context.Options.HasFlag(CompilerOptions.CheckNullReferences))
                {
                    result = true;
                    il.Dup();                              // stack: [array, array]
                    il.Brfalse(returnDefaultValueLabel);   // if(array == null) goto returnDefaultValue; stack: [array]
                }
                EmitLoadIndex(zindex, context, arrayType); // stack: [array, arrayIndex]
                if (context.Options.HasFlag(CompilerOptions.CheckArrayIndexes))
                {
                    result     = true;
                    arrayIndex = context.DeclareLocal(typeof(int));
                    il.Stloc(arrayIndex); // arrayIndex = index; stack: [array]
                    il.Dup();             // stack: [array, array]
                    if (isArray)
                    {
                        il.Ldlen(); // stack: [array, array.Length]
                    }
                    else
                    {
                        EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic));
                    }
                    il.Ldloc(arrayIndex);                   // stack: [array, array.Length, arrayIndex]
                    il.Ble(returnDefaultValueLabel, false); // if(array.Length <= arrayIndex) goto returnDefaultValue; stack: [array]
                    il.Ldloc(arrayIndex);                   // stack: [array, arrayIndex]
                    il.Ldc_I4(0);                           // stack: [array, arrayIndex, 0]
                    il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array]
                }
                else if (extendArrayElement || !isArray)
                {
                    arrayIndex = context.DeclareLocal(typeof(int));
                    il.Stloc(arrayIndex); // arrayIndex = index; stack: [array]
                }
            }
            else
            {
                EmittingContext.LocalHolder arrayOwner = null;
                switch (zarr.NodeType)
                {
                case ExpressionType.Parameter:
                case ExpressionType.ArrayIndex:
                case ExpressionType.Index:
                    Type type;
                    ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.ByRefAll, true, out type); // stack: [ref array]
                    arrayOwner = context.DeclareLocal(type);
                    il.Dup();                                                                                                       // stack: [ref array, ref array]
                    il.Stloc(arrayOwner);                                                                                           // arrayOwner = ref array; stack: [ref array]
                    il.Ldind(zarr.Type);                                                                                            // stack: [array]
                    break;

                case ExpressionType.MemberAccess:
                    var  memberExpression = (MemberExpression)zarr;
                    Type memberType;
                    context.EmitMemberAccess(memberExpression, returnDefaultValueLabel, context.Options.HasFlag(CompilerOptions.CheckNullReferences), true, ResultType.ByRefValueTypesOnly, out memberType, out arrayOwner); // stack: [array]
                    break;

                default:
                    throw new InvalidOperationException("Cannot extend array for expression with node type '" + zarr.NodeType + "'");
                }
                if (context.Options.HasFlag(CompilerOptions.CheckNullReferences))
                {
                    il.Dup();                            // stack: [array, array]
                    il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array]
                }
                EmitLoadIndex(zindex, context, arrayType);
                result     = true;
                arrayIndex = context.DeclareLocal(typeof(int));
                il.Stloc(arrayIndex);                   // arrayIndex = index; stack: [array]
                il.Ldloc(arrayIndex);                   // stack: [array, arrayIndex]
                il.Ldc_I4(0);                           // stack: [array, arrayIndex, 0]
                il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array]
                il.Dup();                               // stack: [array, array]
                if (isArray)
                {
                    il.Ldlen(); // stack: [array, array.Length]
                }
                else
                {
                    EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic));
                }
                il.Ldloc(arrayIndex);          // stack: [array, array.Length, arrayIndex]
                var bigEnoughLabel = il.DefineLabel("bigEnough");
                il.Bgt(bigEnoughLabel, false); // if(array.Length > arrayIndex) goto bigEnough; stack: [array]
                using (var array = context.DeclareLocal(arrayType))
                {
                    il.Stloc(array); // stack: []
                    if (!isArray)
                    {
                        EnsureCount(context, array, arrayIndex, arrayType);
                    }
                    else
                    {
                        il.Ldloca(array);                                                         // stack: [ref array]
                        il.Ldloc(arrayIndex);                                                     // stack: [ref array, arrayIndex]
                        il.Ldc_I4(1);                                                             // stack: [ref array, arrayIndex, 1]
                        il.Add();                                                                 // stack: [ref array, arrayIndex + 1]
                        il.Call(arrayResizeMethod.MakeGenericMethod(arrayType.GetElementType())); // Array.Resize(ref array, 1 + arrayIndex); stack: []

                        switch (zarr.NodeType)
                        {
                        case ExpressionType.Parameter:
                        case ExpressionType.ArrayIndex:
                        case ExpressionType.Index:
                            il.Ldloc(arrayOwner); // stack: [ref parameter]
                            il.Ldloc(array);      // stack: [ref parameter, array]
                            il.Stind(arrayType);  // parameter = array; stack: []
                            break;

                        case ExpressionType.MemberAccess:
                            var memberExpression = (MemberExpression)zarr;
                            if (memberExpression.Expression != null)
                            {
                                il.Ldloc(arrayOwner);
                            }
                            il.Ldloc(array);
                            switch (memberExpression.Member.MemberType)
                            {
                            case MemberTypes.Field:
                                il.Stfld((FieldInfo)memberExpression.Member);
                                break;

                            case MemberTypes.Property:
                                var propertyInfo = (PropertyInfo)memberExpression.Member;
                                var setter       = propertyInfo.GetSetMethod(context.SkipVisibility);
                                if (setter == null)
                                {
                                    throw new MissingMethodException(propertyInfo.ReflectedType.ToString(), "set_" + propertyInfo.Name);
                                }
                                il.Call(setter, memberExpression.Expression == null ? null : memberExpression.Expression.Type);
                                break;

                            default:
                                throw new NotSupportedException("Member type '" + memberExpression.Member.MemberType + "' is not supported");
                            }
                            break;

                        default:
                            throw new InvalidOperationException("Unable to assign array to an expression with node type '" + zarr.NodeType);
                        }
                    }
                    il.Ldloc(array);
                    context.MarkLabelAndSurroundWithSP(bigEnoughLabel);
                }
            }

            if (!isArray)
            {
                // TODO: это злобно, лист при всех операциях меняет _version, а мы нет
                EmitLoadField(context, arrayType, arrayType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic));
                arrayType = itemType.MakeArrayType();
            }

            if (extendArrayElement)
            {
                // stack: [array]
                var constructor = itemType.GetConstructor(Type.EmptyTypes);
                if (itemType.IsArray || constructor != null)
                {
                    using (var array = context.DeclareLocal(arrayType))
                    {
                        il.Dup();             // stack: [array, array]
                        il.Stloc(array);      // stack: [array]
                        il.Ldloc(arrayIndex); // stack: [array, arrayIndex]
                        il.Ldelem(itemType);  // stack: [array[arrayIndex]]
                        var elementIsNotNullLabel = il.DefineLabel("elementIsNotNull");
                        il.Brtrue(elementIsNotNullLabel);
                        il.Ldloc(array);
                        il.Ldloc(arrayIndex);
                        context.Create(itemType);
                        il.Stelem(itemType);
                        context.MarkLabelAndSurroundWithSP(elementIsNotNullLabel);
                        il.Ldloc(array);
                    }
                }
            }
            if (arrayIndex != null)
            {
                il.Ldloc(arrayIndex);
                arrayIndex.Dispose();
            }
            switch (whatReturn)
            {
            case ResultType.ByRefAll:
                il.Ldelema(itemType);
                resultType = itemType.MakeByRefType();
                break;

            case ResultType.ByRefValueTypesOnly:
                if (itemType.IsValueType)
                {
                    il.Ldelema(itemType);
                    resultType = itemType.MakeByRefType();
                }
                else
                {
                    il.Ldelem(itemType); // stack: [array[arrayIndex]]
                    resultType = itemType;
                }
                break;

            default:
                il.Ldelem(itemType); // stack: [array[arrayIndex]]
                resultType = itemType;
                break;
            }
            return(result);
        }