예제 #1
0
 public static void ReadObjectNull(GroboIL il, GroboIL.Label finishMethod, GroboIL.Local buffer, GroboIL.Local offset, GroboIL.Local typeSize)
 {
     il.Ldloc(buffer);
     il.Ldloc(offset);
     il.Ldelem(typeof(byte));
     WriteOffsetAppend(il, offset, 1);
     il.Brtrue(finishMethod);
 }
예제 #2
0
        private static void EmitCrashIfValueIsNull(GroboIL il)
        {
            var box = il.DefineLabel("box");

            il.Dup();
            il.Brtrue(box);
            var crashConstructor = typeof(ArgumentException).GetConstructor(new[] { typeof(string) });

            il.Ldstr("bad parameter");
            il.Newobj(crashConstructor);
            il.Throw();
            il.MarkLabel(box);
        }
예제 #3
0
        public static void WriteObjectNull(GroboIL il, GroboIL.Label finishMethod, GroboIL.Local buffer, GroboIL.Local offset, GroboIL.Local typeSize)
        {
            var _null = il.DeclareLocal(typeof(bool));

            il.Ldnull();
            il.Ceq();
            il.Stloc(_null);

            il.Ldloc(buffer);
            il.Ldloc(offset);

            il.Ldloc(_null);

            il.Stelem(typeof(byte));

            WriteOffsetAppend(il, offset, 1);

            il.Ldloc(_null);
            il.Brtrue(finishMethod);
        }
예제 #4
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestBrtrue()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(C2) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                il.Dup();
                var label = il.DefineLabel("L");
                il.Brtrue(label);
                var label2 = il.DefineLabel("L");
                il.Br(label2);
                il.MarkLabel(label);
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2()));
                il.MarkLabel(label2);
                il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null)));
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
        }
        private static Func <object, object> EmitResolveVarArgsMethod()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var VarArgMethod_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.VarArgMethod");
                if (VarArgMethod_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.VarArgMethod'");
                }
                il.Ldarg(0);               // stack: [value]
                il.Isinst(VarArgMethod_t); // stack: [(VarArgMethod)value]
                var retLabel = il.DefineLabel("ret");
                il.Dup();                  // stack: [(VarArgMethod)value, (VarArgMethod)value]
                il.Brfalse(retLabel);      // if(!(value is VarArgMethod)) goto ret; stack: [value as VarArgMethod]
                var m_method_f = VarArgMethod_t.GetField("m_method", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_method_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_method'");
                }
                var m_dynamicMethod_f = VarArgMethod_t.GetField("m_dynamicMethod", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_dynamicMethod_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_dynamicMethod'");
                }
                var temp = il.DeclareLocal(VarArgMethod_t);
                il.Dup();
                il.Stloc(temp);              // temp = (VarArgMethod)value; stack: [(VarArgMethod)value]
                il.Ldfld(m_method_f);        // stack: [((VarArgMethod)value).m_method]
                il.Dup();                    // stack: [((VarArgMethod)value).m_method, ((VarArgMethod)value).m_method]
                il.Brtrue(retLabel);         // if(((VarArgMethod)value).m_method != null) goto ret; stack: [((VarArgMethod)value).m_method]
                il.Pop();                    // stack: []
                il.Ldloc(temp);              // stack: [(VarArgMethod)value]
                il.Ldfld(m_dynamicMethod_f); // stack: [((VarArgMethod)value).m_dynamicMethod]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>)));
        }
예제 #6
0
        public static void WriteNullableType <T>(GroboIL il, GroboIL.Label finishMethod, GroboIL.Local buffer, GroboIL.Local offset)
            where T : struct
        {
            var _null = il.DeclareLocal(typeof(bool));

            il.Call(typeof(Nullable <T>).GetProperty("HasValue").GetGetMethod());
            il.Ldc_I4(0);
            //il.Ldnull();
            il.Ceq();
            il.Stloc(_null);

            il.Ldloc(buffer);
            il.Ldloc(offset);

            il.Ldloc(_null);

            il.Stelem(typeof(byte));

            WriteOffsetAppend(il, offset, 1);

            il.Ldloc(_null);
            il.Brtrue(finishMethod);
        }
예제 #7
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestEnumerable()
        {
            var assembly             = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.RunAndSave);
            var module               = assembly.DefineDynamicModule(Guid.NewGuid().ToString(), "test.cil", true);
            var symWriter            = module.GetSymWriter();
            var symbolDocumentWriter = symWriter.DefineDocument("test.cil", Guid.Empty, Guid.Empty, Guid.Empty);
            var typeBuilder          = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public);
            var method               = typeBuilder.DefineMethod("Qzz", MethodAttributes.Public);
            var genericParameters    = method.DefineGenericParameters("TZzz");
            var parameter            = genericParameters[0];

            method.SetParameters(typeof(List <>).MakeGenericType(parameter), typeof(Func <,>).MakeGenericType(parameter, typeof(int)));
            method.DefineParameter(2, ParameterAttributes.In, "list");
            method.SetReturnType(typeof(int));
            using (var il = new GroboIL(method, symbolDocumentWriter))
            {
                il.Ldarg(1);
                il.Dup();
                var notNullLabel = il.DefineLabel("notNull");
                il.Brtrue(notNullLabel);
                il.Pop();
                il.Ldc_I4(0);
                il.Newarr(parameter);
                il.MarkLabel(notNullLabel);
                var temp = il.DeclareLocal(typeof(IEnumerable <>).MakeGenericType(parameter), "arr");
                il.Stloc(temp);
                il.Ldloc(temp);
                il.Ldarg(2);
                il.Call(HackHelpers.GetMethodDefinition <int[]>(ints => ints.Sum(x => x)).GetGenericMethodDefinition().MakeGenericMethod(parameter));
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
            var type     = typeBuilder.CreateType();
            var instance = Activator.CreateInstance(type);

            type.GetMethod("Qzz", BindingFlags.Instance | BindingFlags.Public).MakeGenericMethod(typeof(int)).Invoke(instance, new object[] { null, null });
        }
예제 #8
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));
        }
예제 #9
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);
            var len = il.DeclareLocal(typeof(int));


            if (prop.PropertyInfo != null)
            {
                il.Ldloc(value);
                il.Call(prop.ArraySizeProperty.Getter);
                il.Stloc(len);
            }
            else
            {
                il.Ldc_I4(prop.ArraySize);
                il.Stloc(len);
            }

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);

            var type = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];

            var ivar         = il.DeclareLocal(typeof(int));
            var currentValue = il.DeclareLocal(type);
            var point        = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            il.MarkLabel(point);

            //body


            il.Ldloc(arr);
            il.Ldloc(ivar);
            il.Call(prop.PropertyInfo.PropertyType.GetMethod("get_Item"), isVirtual: true);
            il.Stloc(currentValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(type, currentStruct.Scheme), il, binaryStruct, currentValue, buffer, offset, typeSize);
            }
            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);
        }
        protected override bool EmitInternal(SwitchExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL il           = context.Il;
            var     defaultLabel = il.DefineLabel("default");
            var     caseLabels   = new GroboIL.Label[node.Cases.Count];

            GroboIL.Label switchValueIsNullLabel = null;
            for (int index = 0; index < node.Cases.Count; index++)
            {
                caseLabels[index] = il.DefineLabel("case#" + index);
            }
            context.EmitLoadArguments(node.SwitchValue);
            using (var switchValue = context.DeclareLocal(node.SwitchValue.Type))
            {
                il.Stloc(switchValue);
                Tuple <int, int, int> switchCase;
                if (context.ParsedLambda.ParsedSwitches.TryGetValue(node, out switchCase))
                {
                    // use simplified hashtable to locate the proper case
                    var labels = new List <GroboIL.Label>();
                    for (int index = 0; index < node.Cases.Count; index++)
                    {
                        foreach (var testValue in node.Cases[index].TestValues)
                        {
                            if (((ConstantExpression)testValue).Value != null)
                            {
                                labels.Add(caseLabels[index]);
                            }
                            else
                            {
                                switchValueIsNullLabel = caseLabels[index];
                            }
                        }
                    }
                    if (switchValueIsNullLabel != null)
                    {
                        if (!node.SwitchValue.Type.IsNullable())
                        {
                            il.Ldloc(switchValue);
                        }
                        else
                        {
                            il.Ldloca(switchValue);
                            context.EmitHasValueAccess(node.SwitchValue.Type);
                        }
                        il.Brfalse(switchValueIsNullLabel);
                    }
                    EmittingContext.LocalHolder pureSwitchValue = switchValue;
                    if (node.SwitchValue.Type.IsNullable())
                    {
                        pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]);
                        il.Ldloca(switchValue);
                        context.EmitValueAccess(node.SwitchValue.Type);
                        il.Stloc(pureSwitchValue);
                    }
                    Type temp;
                    ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item1), context, out temp);
                    var type     = node.SwitchValue.Type.IsNullable() ? node.SwitchValue.Type.GetGenericArguments()[0] : node.SwitchValue.Type;
                    var typeCode = Type.GetTypeCode(type);
                    switch (typeCode)
                    {
                    case TypeCode.Byte:
                    case TypeCode.Char:
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                    case TypeCode.SByte:
                    case TypeCode.UInt16:
                    case TypeCode.UInt32:
                    case TypeCode.UInt64:
                        il.Ldloc(pureSwitchValue);
                        break;

                    default:
                        if (type.IsValueType)
                        {
                            il.Ldloca(pureSwitchValue);
                        }
                        else
                        {
                            il.Ldloc(pureSwitchValue);
                        }
                        il.Call(typeof(object).GetMethod("GetHashCode"), type);
                        break;
                    }
                    using (var index = context.DeclareLocal(typeof(int)))
                    {
                        if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64)
                        {
                            il.Ldc_I8(switchCase.Item3);
                        }
                        else
                        {
                            il.Ldc_I4(switchCase.Item3);
                        }
                        il.Rem(true);
                        if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64)
                        {
                            il.Conv <int>();
                        }
                        il.Stloc(index);
                        il.Ldloc(index);
                        il.Ldelem(type);
                        il.Ldloc(pureSwitchValue);
                        if (node.Comparison != null)
                        {
                            il.Call(node.Comparison);
                        }
                        else
                        {
                            il.Ceq();
                        }
                        il.Brfalse(defaultLabel);
                        ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item2), context, out temp);
                        il.Ldloc(index);
                        il.Ldelem(typeof(int));
                        il.Switch(labels.ToArray());
                    }
                    if (pureSwitchValue != switchValue)
                    {
                        pureSwitchValue.Dispose();
                    }
                }
                else
                {
                    // use a number of if/else branches to locate the proper case
                    EmittingContext.LocalHolder pureSwitchValue   = switchValue;
                    EmittingContext.LocalHolder switchValueIsNull = null;
                    if (node.SwitchValue.Type.IsNullable())
                    {
                        pureSwitchValue   = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]);
                        switchValueIsNull = context.DeclareLocal(typeof(bool));
                        il.Ldloca(switchValue);
                        il.Dup();
                        context.EmitValueAccess(node.SwitchValue.Type);
                        il.Stloc(pureSwitchValue);
                        context.EmitHasValueAccess(node.SwitchValue.Type);
                        il.Stloc(switchValueIsNull);
                    }
                    for (int index = 0; index < node.Cases.Count; index++)
                    {
                        var caSe  = node.Cases[index];
                        var label = caseLabels[index];
                        foreach (var testValue in caSe.TestValues)
                        {
                            context.EmitLoadArguments(testValue);
                            GroboIL.Label elseLabel = null;
                            if (testValue.Type.IsNullable())
                            {
                                elseLabel = il.DefineLabel("else");
                                using (var temp = context.DeclareLocal(testValue.Type))
                                {
                                    il.Stloc(temp);
                                    il.Ldloca(temp);
                                    context.EmitHasValueAccess(testValue.Type);
                                    if (switchValueIsNull != null)
                                    {
                                        il.Ldloc(switchValueIsNull);
                                        il.Or();
                                        il.Brfalse(label);
                                        il.Ldloca(temp);
                                        context.EmitHasValueAccess(testValue.Type);
                                        il.Ldloc(switchValueIsNull);
                                        il.And();
                                    }
                                    il.Brfalse(elseLabel);
                                    il.Ldloca(temp);
                                    context.EmitValueAccess(testValue.Type);
                                }
                            }
                            il.Ldloc(pureSwitchValue);
                            if (node.Comparison != null)
                            {
                                il.Call(node.Comparison);
                            }
                            else
                            {
                                il.Ceq();
                            }
                            il.Brtrue(label);
                            if (elseLabel != null)
                            {
                                context.MarkLabelAndSurroundWithSP(elseLabel);
                            }
                        }
                    }
                }
            }
            context.MarkLabelAndSurroundWithSP(defaultLabel);
            var doneLabel = il.DefineLabel("done");

            context.EmitLoadArguments(node.DefaultBody);
            il.Br(doneLabel);
            for (int index = 0; index < node.Cases.Count; ++index)
            {
                context.MarkLabelAndSurroundWithSP(caseLabels[index]);
                context.EmitLoadArguments(node.Cases[index].Body);
                if (index < node.Cases.Count - 1)
                {
                    il.Br(doneLabel);
                }
            }
            context.MarkLabelAndSurroundWithSP(doneLabel);
            resultType = node.Type;
            return(false);
        }
예제 #11
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);

            var exitLabel = il.DefineLabel("exit");

            BinaryStruct.WriteSizeChecker(il, buffer, offset, 5);

            BinaryStruct.WriteObjectNull(il, exitLabel, arr, buffer, offset, typeSize);

            var arrSize = il.DeclareLocal(typeof(byte[]));
            var len     = il.DeclareLocal(typeof(int));

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Call(typeof(ICollection).GetProperty("Count").GetMethod);
            il.Stloc(len);

            il.Ldloc(len);
            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arrSize);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arrSize);
            il.Ldc_I4(0);
            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            for (int i = 1; i < 4; i++)
            {
                il.Ldloc(buffer);
                il.Ldloc(offset);
                il.Ldc_I4(i);
                il.Add();
                il.Ldloc(arrSize);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }

            BinaryStruct.WriteOffsetAppend(il, offset, 4);


            il.Ldloc(len);
            il.Ldc_I4(0);
            il.Ceq();
            il.Brtrue(exitLabel);

            var type = prop.PropertyInfo.PropertyType.GetElementType();

            var ivar         = il.DeclareLocal(typeof(int));
            var currentValue = il.DeclareLocal(type);
            var point        = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            il.MarkLabel(point);

            //body


            il.Ldloc(arr);
            il.Ldloc(ivar);
            il.Ldelem(type);
            //il.Call(prop.PropertyInfo.PropertyType.GetMethod("Get"), isVirtual: true);
            il.Stloc(currentValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(type, currentStruct.Scheme), il, binaryStruct, currentValue, buffer, offset, typeSize);
            }

            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);

            il.MarkLabel(exitLabel);
        }
예제 #12
0
        public bool EmitMemberAccess(MemberExpression node, GroboIL.Label returnDefaultValueLabel, bool checkNullReferences, bool extend, ResultType whatReturn, out Type resultType, out LocalHolder owner)
        {
            bool result = false;

            owner = null;
            Type    type = node.Expression == null ? null : node.Expression.Type;
            Type    ownerType;
            GroboIL il = Il;

            if (node.Expression == null)
            {
                ownerType = null;
            }
            else
            {
                result |= ExpressionEmittersCollection.Emit(node.Expression, this, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out type); // stack: [obj]
                if (!type.IsValueType)
                {
                    ownerType = type;
                }
                else
                {
                    ownerType = type.MakeByRefType();
                    using (var temp = DeclareLocal(type))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                }
                if (checkNullReferences && node.Expression != ParsedLambda.ClosureParameter && node.Expression != ParsedLambda.ConstantsParameter && !node.Expression.Type.IsStaticClosure())
                {
                    result |= EmitNullChecking(node.Expression.Type, returnDefaultValueLabel);
                }
            }
            extend &= CanAssign(node.Member);
            Type            memberType  = GetMemberType(node.Member);
            ConstructorInfo constructor = memberType.GetConstructor(Type.EmptyTypes);

            extend &= (memberType.IsClass && constructor != null) || memberType.IsArray;
            if (!extend)
            {
                EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
            }
            else
            {
                if (node.Expression == null)
                {
                    EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
                    var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull");
                    il.Dup();
                    il.Brtrue(memberIsNotNullLabel);
                    il.Pop();
                    Create(memberType);
                    using (var newobj = DeclareLocal(memberType))
                    {
                        il.Stloc(newobj);
                        il.Ldloc(newobj);
                        EmitMemberAssign(type, node.Member);
                        il.Ldloc(newobj);
                    }
                    MarkLabelAndSurroundWithSP(memberIsNotNullLabel);
                }
                else
                {
                    owner = DeclareLocal(ownerType);
                    il.Stloc(owner);
                    il.Ldloc(owner);
                    EmitMemberAccess(type, node.Member, whatReturn, out resultType); // stack: [obj.member]
                    var memberIsNotNullLabel = il.DefineLabel("memberIsNotNull");
                    il.Dup();
                    il.Brtrue(memberIsNotNullLabel);
                    il.Pop();
                    il.Ldloc(owner);
                    Create(memberType);
                    using (var newobj = DeclareLocal(memberType))
                    {
                        il.Stloc(newobj);
                        il.Ldloc(newobj);
                        EmitMemberAssign(type, node.Member);
                        il.Ldloc(newobj);
                    }
                    MarkLabelAndSurroundWithSP(memberIsNotNullLabel);
                }
            }
            return(result);
        }
예제 #13
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);
        }
예제 #14
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            BinaryStruct.WriteSizeChecker(il, buffer, offset, 5);

            var arr       = il.DeclareLocal(typeof(byte[]));
            var arrSize   = il.DeclareLocal(typeof(byte[]));
            var temp      = il.DeclareLocal(typeof(string));
            var exitLabel = il.DefineLabel("exit");


            il.Ldloc(value);

            if (!listValue)
            {
                il.Call(prop.Getter);
            }
            il.Stloc(temp);

            il.Ldloc(temp);
            BinaryStruct.WriteObjectNull(il, exitLabel, buffer, offset, typeSize);

            il.Ldloc(temp);
            il.Call(typeof(string).GetProperty("Length").GetMethod);
            il.Stloc(typeSize);

            il.Ldarg(1);
            il.Call(codingMethodInfo);

            il.Ldloc(temp);

            il.Call(currentStruct.Coding.GetType().GetMethod("GetBytes", new Type[] { typeof(string) }));
            il.Stloc(arr);

            il.Ldloc(arr);
            il.Call(typeof(byte[]).GetProperty("Length").GetMethod);
            il.Stloc(typeSize);

            il.Ldloc(typeSize);
            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arrSize);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arrSize);
            il.Ldc_I4(0);
            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            for (int i = 1; i < 4; i++)
            {
                il.Ldloc(buffer);
                il.Ldloc(offset);
                il.Ldc_I4(i);
                il.Add();
                il.Ldloc(arrSize);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }

            BinaryStruct.WriteOffsetAppend(il, offset, 4);

            il.Ldloc(typeSize);
            il.Ldc_I4(0);
            il.Ceq();
            il.Brtrue(exitLabel);

            BinaryStruct.WriteSizeChecker(il, buffer, offset, typeSize);

            var ivar  = il.DeclareLocal(typeof(int));
            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            il.MarkLabel(point);

            //body

            il.Ldloc(buffer);
            il.Ldloc(ivar);
            il.Ldloc(offset);
            il.Add();
            il.Ldloc(arr);
            il.Ldloc(ivar);

            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(typeSize);

            il.Clt(false);
            il.Brtrue(point);

            BinaryStruct.WriteOffsetAppend(il, offset, typeSize);

            il.MarkLabel(exitLabel);
        }
예제 #15
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);
            var len = il.DeclareLocal(typeof(int));

            if (prop.PropertyInfo != null)
            {
                il.Ldloc(value);
                il.Call(prop.ArraySizeProperty.Getter);
                il.Stloc(len);
            }
            else
            {
                il.Ldc_I4(prop.ArraySize);
                il.Stloc(len);
            }

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);

            var typeKey   = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];
            var typeValue = prop.PropertyInfo.PropertyType.GetGenericArguments()[1];

            var ivar             = il.DeclareLocal(typeof(int));
            var currentItemKey   = il.DeclareLocal(typeKey);
            var currentItemValue = il.DeclareLocal(typeValue);

            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            var enumeratorMethod = prop.PropertyInfo.PropertyType.GetMethod("GetEnumerator");

            var enumerator = il.DeclareLocal(enumeratorMethod.ReturnType);

            var moveNext   = enumerator.Type.GetMethod("MoveNext");
            var getCurrent = enumerator.Type.GetMethod("get_Current");

            var temp  = il.DeclareLocal(getCurrent.ReturnType);
            var exist = il.DeclareLocal(typeof(bool));

            il.Ldloc(arr);
            il.Call(enumeratorMethod, isVirtual: true);
            il.Stloc(enumerator);

            var keyGetter   = getCurrent.ReturnType.GetMethod("get_Key");
            var valueGetter = getCurrent.ReturnType.GetMethod("get_Value");

            il.MarkLabel(point);

            //body

            il.Ldloca(enumerator);
            il.Call(moveNext, enumerator.Type);
            il.Stloc(exist);

            il.Ldloca(enumerator);
            //il.Calli(CallingConventions.Any, typeof(KeyValuePair<int, int>),new Type[] { typeof(int),typeof(int) });
            il.Call(getCurrent, enumerator.Type);
            il.Stloc(temp);

            il.Ldloca(temp);
            il.Call(keyGetter, typeof(int));
            il.Stloc(currentItemKey);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemKey, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeKey, currentStruct.Scheme), il, binaryStruct, currentItemKey, buffer, offset, typeSize);
            }

            il.Ldloca(temp);
            il.Call(valueGetter);
            il.Stloc(currentItemValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[1]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[1]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeValue, currentStruct.Scheme), il, binaryStruct, currentItemValue, buffer, offset, typeSize);
            }
            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);
        }
예제 #16
0
        internal static void Resize(GroboIL il, GroboIL.Local buffer, GroboIL.Local offset /*, GroboIL.Local len*/)
        {
            var totalLen = il.DeclareLocal(typeof(int));

            //offset add typesize = minSize
            il.Ldloc(offset);
            il.Add();
            il.Stloc(totalLen);


            var exit = il.DefineLabel("exit");

            //Compare if minSize < buffer.len
            il.Ldloc(totalLen);
            il.Ldloc(buffer);
            il.Ldlen();
            il.Clt(false);
            il.Brtrue(exit);


            var avar = il.DeclareLocal(typeof(byte));

            il.Ldc_I4(2);
            il.Stloc(avar);

            var point = il.DefineLabel("for_label");

            il.MarkLabel(point);

            //body

            il.Ldloc(avar);
            il.Ldc_I4(2);
            il.Mul();
            il.Stloc(avar);

            //end body


            il.Ldloc(buffer);
            il.Ldlen();
            il.Ldloc(avar);
            il.Mul();
            //OutputValue(il,typeof(int));

            il.Ldloc(totalLen);
            //OutputValue(il, typeof(int));

            il.Clt(false);
            //OutputValue(il, typeof(bool));
            il.Brtrue(point);

            il.Ldloca(buffer);

            il.Ldloc(avar);
            il.Ldloc(buffer);
            il.Ldlen();
            il.Mul();
            //OutputValue(il, typeof(int));

            il.Call(typeof(Array).GetMethod("Resize", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(typeof(byte)));


            il.MarkLabel(exit);
        }
예제 #17
0
        public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue)
        {
            var arr = il.DeclareLocal(prop.PropertyInfo.PropertyType);

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Stloc(arr);
            var exitLabel = il.DefineLabel("exit");

            BinaryStruct.WriteSizeChecker(il, buffer, offset, 3);

            BinaryStruct.WriteObjectNull(il, exitLabel, arr, buffer, offset, typeSize);

            var arrSize = il.DeclareLocal(typeof(byte[]));
            var len     = il.DeclareLocal(typeof(short));

            il.Ldloc(value);
            il.Call(prop.Getter);
            il.Call(typeof(ICollection).GetProperty("Count").GetMethod);
            il.Stloc(len);

            il.Ldloc(len);
            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arrSize);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arrSize);
            il.Ldc_I4(0);
            il.Ldelem(typeof(byte));
            il.Stelem(typeof(byte));

            for (int i = 1; i < 2; i++)
            {
                il.Ldloc(buffer);
                il.Ldloc(offset);
                il.Ldc_I4(i);
                il.Add();
                il.Ldloc(arrSize);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }

            BinaryStruct.WriteOffsetAppend(il, offset, 2);

            il.Ldloc(len);
            il.Ldc_I4(0);
            il.Ceq();
            il.Brtrue(exitLabel);

            var typeKey   = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];
            var typeValue = prop.PropertyInfo.PropertyType.GetGenericArguments()[1];

            var ivar             = il.DeclareLocal(typeof(int));
            var currentItemKey   = il.DeclareLocal(typeKey);
            var currentItemValue = il.DeclareLocal(typeValue);

            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            var enumeratorMethod = prop.PropertyInfo.PropertyType.GetMethod("GetEnumerator");

            var enumerator = il.DeclareLocal(enumeratorMethod.ReturnType);

            var moveNext   = enumerator.Type.GetMethod("MoveNext");
            var getCurrent = enumerator.Type.GetMethod("get_Current");

            var temp  = il.DeclareLocal(getCurrent.ReturnType);
            var exist = il.DeclareLocal(typeof(bool));

            il.Ldloc(arr);
            il.Call(enumeratorMethod, isVirtual: true);
            il.Stloc(enumerator);

            var keyGetter   = getCurrent.ReturnType.GetMethod("get_Key");
            var valueGetter = getCurrent.ReturnType.GetMethod("get_Value");

            il.MarkLabel(point);

            //body

            il.Ldloca(enumerator);
            il.Call(moveNext, enumerator.Type);
            il.Stloc(exist);

            il.Ldloca(enumerator);
            il.Call(getCurrent, enumerator.Type);
            il.Stloc(temp);

            il.Ldloca(temp);
            il.Call(keyGetter, typeof(int));
            il.Stloc(currentItemKey);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemKey, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeKey, currentStruct.Scheme), il, binaryStruct, currentItemKey, buffer, offset, typeSize);
            }

            il.Ldloca(temp);
            il.Call(valueGetter);
            il.Stloc(currentItemValue);

            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[1]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[1]);
                t.GetWriteILCode(prop, currentStruct, il, binaryStruct, currentItemValue, typeSize, buffer, offset, true);
            }
            else
            {
                BinaryStruct.CompileWriter(currentStruct.CurrentStorage.GetTypeInfo(typeValue, currentStruct.Scheme), il, binaryStruct, currentItemValue, buffer, offset, typeSize);
            }
            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);


            il.MarkLabel(exitLabel);
        }
        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);
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL il = context.Il;

            if (node.Method != null)
            {
                throw new NotSupportedException("Custom operator '" + node.NodeType + "' is not supported");
            }
            Expression left  = node.Left;
            Expression right = node.Right;
            Type       leftType;

            context.EmitLoadArgument(left, false, out leftType); // stack: [left]
            if (leftType == typeof(bool))
            {
                switch (node.NodeType)
                {
                case ExpressionType.AndAlso:
                {
                    var returnFalseLabel = il.DefineLabel("returnFalse");
                    il.Brfalse(returnFalseLabel);                          // if(left == false) return false; stack: []
                    Type rightType;
                    context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);                                      // goto done; stack: [right]
                    context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                    il.Ldc_I4(0);                                          // stack: [false]
                    if (rightType == typeof(bool?))
                    {
                        il.Newobj(nullableBoolConstructor);     // stack: [new bool?(false)]
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                    resultType = rightType;
                    break;
                }

                case ExpressionType.OrElse:
                {
                    var returnTrueLabel = il.DefineLabel("returnTrue");
                    il.Brtrue(returnTrueLabel);                            // if(left == true) return true; stack: []
                    Type rightType;
                    context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);                                      // goto done; stack: [right]
                    context.MarkLabelAndSurroundWithSP(returnTrueLabel);
                    il.Ldc_I4(1);                                          // stack: [true]
                    if (rightType == typeof(bool?))
                    {
                        il.Newobj(nullableBoolConstructor);     // stack: [new bool?(true)]
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                    resultType = rightType;
                    break;
                }

                default:
                    throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported");
                }
            }
            else // bool?
            {
                switch (node.NodeType)
                {
                case ExpressionType.AndAlso:
                {
                    /*
                     * +-------+-------+-------+-------+
                     * |  &&   | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | null  | null  | false | null  |
                     * +-------+-------+-------+-------+
                     * | false | false | false | false |
                     * +-------+-------+-------+-------+
                     * | true  | null  | false | true  |
                     * +-------+-------+-------+-------+
                     */
                    using (var localLeft = context.DeclareLocal(typeof(bool?)))
                    {
                        il.Stloc(localLeft);                                   // localLeft = left; stack: []
                        il.Ldloca(localLeft);                                  // stack: [&localLeft]
                        context.EmitHasValueAccess(typeof(bool?));             // stack: [localLeft.HasValue]
                        il.Ldc_I4(1);                                          // stack: [localLeft.HasValue, true]
                        il.Xor();                                              // stack: [!localLeft.HasValue]
                        il.Ldloca(localLeft);                                  // stack: [!localLeft.HasValue, &localLeft]
                        context.EmitValueAccess(typeof(bool?));                // stack: [!localLeft.HasValue, localLeft.Value]
                        il.Or();                                               // stack: [!localLeft.HasValue || localLeft.Value]
                        var returnFalseLabel = il.DefineLabel("returnFalse");
                        il.Brfalse(returnFalseLabel);                          // if(localLeft == false) goto returnFalse; stack: []
                        Type rightType;
                        context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                        using (var localRight = context.DeclareLocal(rightType))
                        {
                            il.Stloc(localRight);     // localRight = right; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldc_I4(1);                              // stack: [localRight.HasValue, true]
                                il.Xor();                                  // stack: [!localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [!localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [!localRight.HasValue, localRight.Value]
                                il.Or();                                   // stack: [!localRight.HasValue || localRight.Value]
                            }
                            il.Brfalse(returnFalseLabel);                  // if(localRight == false) goto returnFalse;
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [localRight.HasValue, localRight.Value]
                                il.And();                                  // stack: [localRight.HasValue && localRight.Value]
                            }
                            var returnLeftLabel = il.DefineLabel("returnLeft");
                            il.Brtrue(returnLeftLabel); // if(localRight == true) goto returnLeft;
                            il.Ldloca(localLeft);       // stack: [&localLeft]
                            il.Initobj(typeof(bool?));  // localLeft = default(bool?); stack: []
                            context.MarkLabelAndSurroundWithSP(returnLeftLabel);
                            il.Ldloc(localLeft);        // stack: [localLeft]
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                            il.Ldc_I4(0);                       // stack: [false]
                            il.Newobj(nullableBoolConstructor); // new bool?(false)
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            resultType = typeof(bool?);
                        }
                    }
                    break;
                }

                case ExpressionType.OrElse:
                {
                    /*
                     * +-------+-------+-------+-------+
                     * |  ||   | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | null  | null  | null  | true  |
                     * +-------+-------+-------+-------+
                     * | false | null  | false | true  |
                     * +-------+-------+-------+-------+
                     * | true  | true  | true  | true  |
                     * +-------+-------+-------+-------+
                     */
                    using (var localLeft = context.DeclareLocal(typeof(bool?)))
                    {
                        il.Stloc(localLeft);                                   // localLeft = left; stack: []
                        il.Ldloca(localLeft);                                  // stack: [&localLeft]
                        context.EmitHasValueAccess(typeof(bool?));             // stack: [localLeft.HasValue]
                        il.Ldloca(localLeft);                                  // stack: [localLeft.HasValue, &localLeft]
                        context.EmitValueAccess(typeof(bool?));                // stack: [localLeft.HasValue, localLeft.Value]
                        il.And();                                              // stack: [localLeft.HasValue && localLeft.Value]
                        var returnTrueLabel = il.DefineLabel("returnTrue");
                        il.Brtrue(returnTrueLabel);                            // if(localLeft == true) goto returnTrue; stack: []
                        Type rightType;
                        context.EmitLoadArgument(right, false, out rightType); // stack: [right]
                        using (var localRight = context.DeclareLocal(rightType))
                        {
                            il.Stloc(localRight);     // localRight = right; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [localRight.HasValue, localRight.Value]
                                il.And();                                  // stack: [localRight.HasValue && localRight.Value]
                            }
                            il.Brtrue(returnTrueLabel);                    // if(localRight == true) goto returnTrue; stack: []
                            if (rightType == typeof(bool))
                            {
                                il.Ldloc(localRight);     // stack: [localRight]
                            }
                            else
                            {
                                il.Ldloca(localRight);                     // stack: [&localRight]
                                context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue]
                                il.Ldc_I4(1);                              // stack: [localRight.HasValue, true]
                                il.Xor();                                  // stack: [!localRight.HasValue]
                                il.Ldloca(localRight);                     // stack: [!localRight.HasValue, &localRight]
                                context.EmitValueAccess(typeof(bool?));    // stack: [!localRight.HasValue, localRight.Value]
                                il.Or();                                   // stack: [!localRight.HasValue || localRight.Value]
                            }
                            var returnLeftLabel = il.DefineLabel("returnLeft");
                            il.Brfalse(returnLeftLabel); // if(localRight == false) goto returnLeft;
                            il.Ldloca(localLeft);        // stack: [&localLeft]
                            il.Initobj(typeof(bool?));   // localLeft = default(bool?); stack: []
                            context.MarkLabelAndSurroundWithSP(returnLeftLabel);
                            il.Ldloc(localLeft);         // stack: [localLeft]
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(returnTrueLabel);
                            il.Ldc_I4(1);                       // stack: [true]
                            il.Newobj(nullableBoolConstructor); // new bool?(true)
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            resultType = typeof(bool?);
                        }
                    }
                    break;
                }

                default:
                    throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported");
                }
            }
            return(false);
        }
예제 #20
0
        public void GetReadILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local buffer, GroboIL.Local result, GroboIL.Local typeSize, GroboIL.Local offset, bool listValue)
        {
            var exitLabel = il.DefineLabel("exit");

            BinaryStruct.ReadObjectNull(il, exitLabel, buffer, offset, typeSize);

            var len  = il.DeclareLocal(typeof(int));
            var list = il.DeclareLocal(prop.PropertyInfo.PropertyType);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Call(readBitConverterMethodInfo);
            il.Stloc(len);

            BinaryStruct.WriteOffsetAppend(il, offset, 4);

            il.Newobj(BinaryStruct.GetConstructor(prop.PropertyInfo.PropertyType, null));

            il.Stloc(list);
            il.Ldloc(result);
            il.Ldloc(list);
            il.Call(prop.Setter, isVirtual: true);

            il.Ldloc(len);
            il.Ldc_I4(0);
            il.Ceq();
            il.Brtrue(exitLabel);

            var typeKey   = prop.PropertyInfo.PropertyType.GetGenericArguments()[0];
            var typeValue = prop.PropertyInfo.PropertyType.GetGenericArguments()[1];

            var ivar             = il.DeclareLocal(typeof(int));
            var currentItemKey   = il.DeclareLocal(typeKey);
            var currentItemValue = il.DeclareLocal(typeValue);

            var point = il.DefineLabel("for_label");

            il.Ldc_I4(0);
            il.Stloc(ivar);

            il.MarkLabel(point);

            //body


            //key
            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[0]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[0]);
                t.GetReadILCode(prop, currentStruct, il, binaryStruct, buffer, currentItemKey, typeSize, offset, true);
            }
            else
            {
                var constr = BinaryStruct.GetConstructor(typeKey, null);
                if (constr == null)
                {
                    throw new Exception($"Type {typeKey} not have constructor with not parameters");
                }

                il.Newobj(constr);
                il.Stloc(currentItemKey);

                BinaryStruct.CompileReader(currentStruct.CurrentStorage.GetTypeInfo(typeKey, currentStruct.Scheme), il, binaryStruct, buffer, offset, currentItemKey, typeSize);
            }

            //value
            if (typeof(IBasicType).IsAssignableFrom(prop.BinaryAttr.Type.GetGenericArguments()[1]))
            {
                IBasicType t = (IBasicType)Activator.CreateInstance(prop.BinaryAttr.Type.GetGenericArguments()[1]);
                t.GetReadILCode(prop, currentStruct, il, binaryStruct, buffer, currentItemValue, typeSize, offset, true);
            }
            else
            {
                var constr = BinaryStruct.GetConstructor(typeValue, null);
                if (constr == null)
                {
                    throw new Exception($"Type {typeValue} not have constructor with not parameters");
                }

                il.Newobj(constr);
                il.Stloc(currentItemValue);

                BinaryStruct.CompileReader(currentStruct.CurrentStorage.GetTypeInfo(typeValue, currentStruct.Scheme), il, binaryStruct, buffer, offset, currentItemValue, typeSize);
            }

            il.Ldloc(list);
            il.Ldloc(currentItemKey);
            il.Ldloc(currentItemValue);
            il.Call(prop.PropertyInfo.PropertyType.GetMethod("Add"), isVirtual: true);

            //end body

            il.Ldc_I4(1);
            il.Ldloc(ivar);
            il.Add();
            il.Stloc(ivar);

            il.Ldloc(ivar);
            il.Ldloc(len);

            il.Clt(false);
            il.Brtrue(point);

            il.MarkLabel(exitLabel);
        }
예제 #21
0
        protected override bool EmitInternal(MethodCallExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var        result = false;
            GroboIL    il     = context.Il;
            var        method = node.Method;
            Expression obj;
            IEnumerable <Expression>    arguments;
            IEnumerable <ParameterInfo> parameters;
            bool isStatic = method.IsStatic;

            if (!isStatic)
            {
                obj        = node.Object;
                arguments  = node.Arguments;
                parameters = method.GetParameters();
            }
            else if (method.DeclaringType == typeof(Enumerable))
            {
                obj        = node.Arguments[0];
                arguments  = node.Arguments.Skip(1);
                parameters = method.GetParameters().Skip(1);
            }
            else
            {
                obj        = null;
                arguments  = node.Arguments;
                parameters = method.GetParameters();
            }
            Type type = obj == null ? null : obj.Type;

            if (obj != null)
            {
                Type actualType;
                result |= ExpressionEmittersCollection.Emit(obj, context, returnDefaultValueLabel, isStatic ? ResultType.Value : ResultType.ByRefValueTypesOnly, extend, out actualType); // stack: [obj]
                if (actualType == typeof(void))
                {
                    throw new InvalidOperationException("Unable to call method on void");
                }
                if (actualType.IsValueType && !isStatic)
                {
                    using (var temp = context.DeclareLocal(actualType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                    actualType = actualType.MakeByRefType();
                }
                if (context.Options.HasFlag(CompilerOptions.CheckNullReferences) && !actualType.IsValueType)
                {
                    if (method.DeclaringType != typeof(Enumerable))
                    {
                        result |= context.EmitNullChecking(type, returnDefaultValueLabel);
                    }
                    else
                    {
                        var arrIsNotNullLabel = il.DefineLabel("arrIsNotNull");
                        il.Dup();
                        il.Brtrue(arrIsNotNullLabel);
                        il.Pop();
                        il.Ldc_I4(0);
                        il.Newarr(GetElementType(type));
                        context.MarkLabelAndSurroundWithSP(arrIsNotNullLabel);
                    }
                }
            }

            var parametersArray = parameters.ToArray();
            var argumentsArray  = arguments.ToArray();

            for (int i = 0; i < argumentsArray.Length; i++)
            {
                var argument  = argumentsArray[i];
                var parameter = parametersArray[i];
                if (parameter.ParameterType.IsByRef)
                {
                    Type argumentType;
                    var  options = context.Options;
                    context.Options = CompilerOptions.None;
                    ExpressionEmittersCollection.Emit(argument, context, null, ResultType.ByRefAll, false, out argumentType);
                    context.Options = options;
                    if (!argumentType.IsByRef)
                    {
                        throw new InvalidOperationException("Expected type by reference");
                    }
                }
                else
                {
                    Type argumentType;
                    context.EmitLoadArgument(argument, true, out argumentType);
                }
            }
            il.Call(method, type);
            resultType = node.Type;
            return(result);
        }