예제 #1
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>)));
        }
        protected override bool EmitInternal(MemberInitExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            ExpressionEmittersCollection.Emit(node.NewExpression, context, out resultType); // stack: [new obj(args)]
            GroboIL il = context.Il;

            if (!node.Type.IsValueType)
            {
                foreach (MemberAssignment assignment in node.Bindings)
                {
                    il.Dup();
                    context.EmitLoadArguments(assignment.Expression);
                    context.EmitMemberAssign(node.Type, assignment.Member);
                }
            }
            else
            {
                using (var temp = context.DeclareLocal(node.Type))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                    foreach (MemberAssignment assignment in node.Bindings)
                    {
                        il.Dup();
                        context.EmitLoadArguments(assignment.Expression);
                        context.EmitMemberAssign(node.Type, assignment.Member);
                    }
                    // todo или il.Ldobj()?
                    il.Pop();
                    il.Ldloc(temp);
                }
            }
            return(false);
        }
예제 #3
0
        public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext)
        {
            var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] { Type, typeof(bool), typeof(WriterContext) }, sizeCounterBuilderContext.Module, true);

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

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

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

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

            sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate);
        }
예제 #4
0
        private static TryParseDelegate EmitTryParseDelegate()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(string), typeof(DateTimeTypeCode), typeof(object).MakeByRefType() }, typeof(string), true);
            var xsdDateTimeType = typeof(XmlReader).Assembly.GetTypes().FirstOrDefault(type => type.Name == "XsdDateTime");

            if (xsdDateTimeType == null)
            {
                throw new InvalidOperationException("The type 'XsdDateTime' is not found");
            }
            var tryParseMethod = xsdDateTimeType.GetMethod("TryParse", BindingFlags.Static | BindingFlags.NonPublic);

            if (tryParseMethod == null)
            {
                throw new InvalidOperationException("The method 'XsdDateTime.TryParse' is not found");
            }
            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [value]
                il.Ldarg(1); // stack: [value, typeCode]
                var strongBoxType = typeof(StrongBox <>).MakeGenericType(xsdDateTimeType);
                var strongBox     = il.DeclareLocal(strongBoxType);
                il.Ldarg(2);                                                                             // stack: [value, typeCode, ref result]
                il.Newobj(strongBoxType.GetConstructor(Type.EmptyTypes));                                // stack: [value, typeCode, ref result, new StrongBox<XsdDateTime>()]
                il.Dup();
                il.Stloc(strongBox);                                                                     // strongBox = new StrongBox<XsdDateTime>(); stack: [value, typeCode, ref result, strongBox]
                il.Stind(typeof(object));                                                                // result = strongBox; stack: [value, typeCode]
                il.Ldloc(strongBox);                                                                     // stack: [value, typeCode, strongBox]
                il.Ldflda(strongBoxType.GetField("Value", BindingFlags.Instance | BindingFlags.Public)); // stack: [value, typeCode, ref strongBox.Value]
                il.Call(tryParseMethod);                                                                 // stack: [XsdDateTime.TryParse(value, typeCode, ref strongBox.Value]
                il.Ret();
            }
            return((TryParseDelegate)method.CreateDelegate(typeof(TryParseDelegate)));
        }
예제 #5
0
        private static Func <MethodBase, DynamicMethod> EmitTryCastToDynamicMethod()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(DynamicMethod), new[] { typeof(MethodBase) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var RTDynamicMethod_t = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic);
                if (RTDynamicMethod_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod'");
                }
                il.Ldarg(0);                  // stack: [method]
                il.Isinst(RTDynamicMethod_t); // stack: [method as RTDynamicMethod]
                il.Dup();                     // stack: [method as RTDynamicMethod, method as RTDynamicMethod]
                var retLabel = il.DefineLabel("ret");
                il.Brfalse(retLabel);         // if(!(method is RTDynamicMethod)] goto ret; stack: [method as RTDynamicMethod]
                var m_owner_f = RTDynamicMethod_t.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_owner_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.DynamicMethod.RTDynamicMethod.m_owner'");
                }
                il.Ldfld(m_owner_f); // stack: [((RTDynamicMethod)method).m_owner]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <MethodBase, DynamicMethod>)method.CreateDelegate(typeof(Func <MethodBase, DynamicMethod>)));
        }
예제 #6
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, 2);
            var arr = il.DeclareLocal(typeof(byte[]));

            il.Ldloc(value);
            if (!listValue)
            {
                il.Call(prop.Getter);
            }
            il.Dup();
            il.Pop();
            il.Call(writeBitConverterMethodInfo);
            il.Stloc(arr);

            il.Ldloc(buffer);
            il.Ldloc(offset);
            il.Ldloc(arr);
            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(arr);
                il.Ldc_I4(i);
                il.Ldelem(typeof(byte));
                il.Stelem(typeof(byte));
            }
            BinaryStruct.WriteOffsetAppend(il, offset, 2);
        }
예제 #7
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestDifferentPathsGeneric()
        {
            var assembly          = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
            var module            = assembly.DefineDynamicModule(Guid.NewGuid().ToString());
            var type              = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public);
            var method            = type.DefineMethod("Qzz", MethodAttributes.Public | MethodAttributes.Static);
            var genericParameters = method.DefineGenericParameters("TZzz");
            var parameter         = genericParameters[0];

            method.SetParameters(typeof(bool), typeof(C1 <>).MakeGenericType(parameter), typeof(C2 <>).MakeGenericType(parameter));
            method.SetReturnType(typeof(void));
            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                var label1 = il.DefineLabel("L1");
                il.Brfalse(label1);
                il.Ldarg(1);
                var label2 = il.DefineLabel("L2");
                il.Br(label2);
                il.MarkLabel(label1);
                il.Ldarg(2);
                il.MarkLabel(label2);
                il.Dup();
                il.Call(HackHelpers.GetMethodDefinition <I1 <int> >(x => F1(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter));
                il.Call(HackHelpers.GetMethodDefinition <I2 <int> >(x => F2(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter));
                il.Ret();
                Console.Write(il.GetILCode());
            }
        }
예제 #8
0
 private static void EmitXPlusPlus(this GroboIL il, GroboIL.Local intLocal)
 {
     il.Ldloc(intLocal);
     il.Dup();
     il.Ldc_I4(1);
     il.Add();
     il.Stloc(intLocal);
 }
예제 #9
0
 private static void EmitMinusMinusX(this GroboIL il, GroboIL.Local intLocal)
 {
     il.Ldloc(intLocal);
     il.Ldc_I4(1);
     il.Sub();
     il.Dup();
     il.Stloc(intLocal);
 }
        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>)));
        }
예제 #11
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);
        }
        private static Func <object, object> EmitResolveGenericMethodInfo()
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                var GenericMethodInfo_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.GenericMethodInfo");
                if (GenericMethodInfo_t == null)
                {
                    throw new InvalidOperationException("Missing type 'System.Reflection.Emit.GenericMethodInfo'");
                }
                il.Ldarg(0);                    // stack: [value]
                il.Isinst(GenericMethodInfo_t); // stack: [(GenericMethodInfo)value]
                var retLabel = il.DefineLabel("ret");
                il.Dup();                       // stack: [(GenericMethodInfo)value, (GenericMethodInfo)value]
                il.Brfalse(retLabel);           // if(!(value is GenericMethodInfo)) goto ret; stack: [value as GenericMethodInfo]
                var m_methodHandle_f = GenericMethodInfo_t.GetField("m_methodHandle", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_methodHandle_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_methodHandle'");
                }
                var m_context_f = GenericMethodInfo_t.GetField("m_context", BindingFlags.Instance | BindingFlags.NonPublic);
                if (m_context_f == null)
                {
                    throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_context'");
                }
                var temp = il.DeclareLocal(GenericMethodInfo_t);
                il.Dup();
                il.Stloc(temp);                 // temp = (GenericMethodInfo)value; stack: [(GenericMethodInfo)value]
                il.Ldfld(m_methodHandle_f);     // stack: [((GenericMethodInfo)value).m_methodHandle]
                il.Ldloc(temp);                 // stack: [((GenericMethodInfo)value).m_methodHandle, (GenericMethodInfo)value]
                il.Ldfld(m_context_f);          // stack: [((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context]
                var getMethodFromHandle_m = HackHelpers.GetMethodDefinition <int>(x => MethodBase.GetMethodFromHandle(default(RuntimeMethodHandle), default(RuntimeTypeHandle)));
                il.Call(getMethodFromHandle_m); // stack: [MethodBase.GetMethodFromHandle(((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context)]
                il.MarkLabel(retLabel);
                il.Ret();
            }
            return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>)));
        }
예제 #13
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestBrfalse()
        {
            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.Brfalse(label);
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => x.GetI2()));
                il.MarkLabel(label);
                il.Call(HackHelpers.GetMethodDefinition <int>(x => F2(null)));
                il.Ret();
                Console.WriteLine(il.GetILCode());
            }
        }
        protected override bool EmitInternal(TypeBinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            bool    result;
            GroboIL il = context.Il;

            if (!node.Expression.Type.IsAssignableFrom(node.TypeOperand))
            {
                il.Ldc_I4(0);
                result = false;
            }
            else if (node.Expression.Type == node.TypeOperand && node.TypeOperand.IsValueType)
            {
                il.Ldc_I4(1);
                result = false;
            }
            else
            {
                Type operandType;
                result = ExpressionEmittersCollection.Emit(node.Expression, context, returnDefaultValueLabel, ResultType.Value, extend, out operandType);
                if (operandType.IsValueType)
                {
                    using (var temp = context.DeclareLocal(operandType))
                    {
                        il.Stloc(temp);
                        il.Ldloca(temp);
                    }
                }
                var returnFalseLabel = il.DefineLabel("returnFalse");
                il.Dup();
                il.Brfalse(returnFalseLabel);
                il.Call(typeof(object).GetMethod("GetType"), operandType);
                il.Ldtoken(node.TypeOperand);
                il.Call(typeof(Type).GetMethod("GetTypeFromHandle"));
                il.Ceq();
                var doneLabel = il.DefineLabel("done");
                il.Br(doneLabel);
                context.MarkLabelAndSurroundWithSP(returnFalseLabel);
                il.Pop();
                il.Ldc_I4(0);
                context.MarkLabelAndSurroundWithSP(doneLabel);
            }
            resultType = typeof(bool);
            return(result);
        }
예제 #15
0
        private static void BuildChildren(TypeBuilder typeBuilder, int n, Context context)
        {
            var property = typeBuilder.DefineProperty("Children", PropertyAttributes.None, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes);
            var getter   = typeBuilder.DefineMethod("get_Children", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes);

            using (var il = new GroboIL(getter))
            {
                il.Ldc_I4(n);                      // stack: [n]
                il.Newarr(typeof(MethodCallNode)); // stack: [new int[n] -> values]
                for (int i = 0; i < n; ++i)
                {
                    il.Dup();                          // stack: [values, values]
                    il.Ldc_I4(i);                      // stack: [values, values, i]
                    il.Ldarg(0);                       // stack: [values, values, i, this]
                    il.Ldfld(context.values[i]);       // stack: [values, values, i, this.values_{i}]
                    il.Stelem(typeof(MethodCallNode)); // values[i] = this.values_{i}; stack: [values]
                }
                il.Castclass(typeof(IEnumerable <MethodCallNode>));
                il.Ret();
            }
            property.SetGetMethod(getter);
            typeBuilder.DefineMethodOverride(getter, typeof(MethodCallNodeEdges).GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance).GetGetMethod());
        }
예제 #16
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 });
        }
예제 #17
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        public void TestDifferentPaths()
        {
            Console.WriteLine(Formatter.Format(typeof(Dictionary <string, int>).GetProperty("Values", BindingFlags.Public | BindingFlags.Instance).GetGetMethod()));
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(bool), typeof(C1), typeof(C2) }, typeof(string), true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                var label1 = il.DefineLabel("L1");
                il.Brfalse(label1);
                il.Ldarg(1);
                var label2 = il.DefineLabel("L2");
                il.Br(label2);
                il.MarkLabel(label1);
                il.Ldarg(2);
                il.MarkLabel(label2);
                il.Dup();
                il.Call(HackHelpers.GetMethodDefinition <I1>(x => F1(x)));
                il.Call(HackHelpers.GetMethodDefinition <I2>(x => F2(x)));
                il.Ret();
                Console.Write(il.GetILCode());
            }
            var action = method.CreateDelegate(typeof(Action <bool, C1, C2>));
        }
        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);
        }
예제 #19
0
        public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment)
        {
            var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool),
                                           new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true);
            var indices = new List <int>();

            using (var il = new GroboIL(method))
            {
                var idx           = il.DeclareLocal(typeof(int), "idx");
                var retFalseLabel = il.DefineLabel("retFalse");
                for (int i = 0; i < numberOfSegments; ++i)
                {
                    var firstKeyInSegment = keys[i * numberOfKeysPerSegment];
                    var lastKeyInSegment  = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment];
                    il.Ldarg(1);                                                   // stack: [key]
                    il.Ldc_I4(firstKeyInSegment);                                  // stack: [key, firstKey]
                    var nextSegmentLabel = il.DefineLabel("nextSegment");
                    il.Blt(nextSegmentLabel, false);                               // if(key < firstKey) goto nextSegment; stack: []
                    il.Ldarg(1);                                                   // stack: [key]
                    il.Ldc_I4(lastKeyInSegment);                                   // stack: [key, lastKey]
                    il.Bgt(nextSegmentLabel, false);                               // if(key > lastKey) goto nextSegment; stack: []
                    il.Ldarg(0);                                                   // stack: [closure]
                    il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.indices)); // stack: [closure.indices]
                    il.Ldarg(1);                                                   // stack: [closure.indices, key]
                    il.Ldc_I4(firstKeyInSegment - indices.Count);                  // stack: [closure.indices, key, diff]
                    il.Sub();                                                      // stack: [closure.indices, key - diff]
                    il.Ldelem(typeof(int));                                        // stack: [closure.indices[key - diff]]
                    il.Dup();
                    il.Stloc(idx);                                                 // idx = closure.indices[key - diff]; stack: [idx]
                    il.Ldc_I4(0);                                                  // stack: [idx, 0]
                    il.Blt(retFalseLabel, false);                                  // if(idx < 0) goto retFalse; stack: []
                    il.Ldarg(2);                                                   // stack: [ref value]
                    il.Ldarg(0);                                                   // stack: [ref value, closure]
                    il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.values));  // stack: [ref value, closure.values]
                    il.Ldloc(idx);                                                 // stack: [ref value, closure.values, idx]
                    il.Ldelem(typeof(T));                                          // stack: [ref value, closure.values[idx]]
                    il.Stind(typeof(T));                                           // value = closure.values[idx]; stack: []
                    il.Ldc_I4(1);                                                  // stack: [true]
                    il.Ret();
                    il.MarkLabel(nextSegmentLabel);
                    var segmentLength = lastKeyInSegment - firstKeyInSegment + 1;
                    int start         = indices.Count;
                    for (int j = 0; j < segmentLength; ++j)
                    {
                        indices.Add(-1);
                    }
                    for (int j = 0; j < numberOfKeysPerSegment; ++j)
                    {
                        indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j;
                    }
                }
                il.MarkLabel(retFalseLabel);
                il.Ldarg(2); // stack: [ref value]
                if (typeof(T).IsValueType)
                {
                    il.Initobj(typeof(T)); // value = default(T); stack: []
                }
                else
                {
                    il.Ldnull();         // stack: [ref value, null]
                    il.Stind(typeof(T)); // value = null; stack: []
                }
                il.Ldc_I4(0);            // stack: [false]
                il.Ret();
            }
            var closure = new Closure <T>
            {
                indices = indices.ToArray(),
                values  = values
            };

            return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure));
        }
예제 #20
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);
        }
예제 #21
0
 public static void OutputValue(GroboIL il, Type t)
 {
     il.Dup();
     //il.Box(t);
     il.Call(typeof(BinaryStruct).GetMethod("OutputBuffer", BindingFlags.NonPublic | BindingFlags.Static));
 }
        protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            GroboIL      il      = context.Il;
            var          result  = false;
            var          operand = node.Operand;
            Type         assigneeType;
            AssigneeKind assigneeKind;
            bool         checkNullReferences = context.Options.HasFlag(CompilerOptions.CheckNullReferences);

            extend |= context.Options.HasFlag(CompilerOptions.ExtendOnAssign);

            GroboIL.Label assigneeIsNullLabel     = null;
            bool          assigneeIsNullLabelUsed = false;

            switch (operand.NodeType)
            {
            case ExpressionType.Parameter:
                assigneeType        = null;
                assigneeKind        = AssigneeKind.Parameter;
                checkNullReferences = false;
                break;

            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression)operand;
                if (memberExpression.Expression == null)
                {
                    assigneeType        = null;
                    assigneeKind        = memberExpression.Member is FieldInfo ? AssigneeKind.StaticField : AssigneeKind.StaticProperty;
                    checkNullReferences = false;
                }
                else
                {
                    bool closureAssign = memberExpression.Expression == context.ParsedLambda.ClosureParameter || memberExpression.Expression.Type.IsStaticClosure();
                    checkNullReferences &= !closureAssign;
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(memberExpression.Expression, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = !closureAssign && context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(memberExpression.Expression, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = memberExpression.Member is FieldInfo ? AssigneeKind.InstanceField : AssigneeKind.InstanceProperty;
                }
                break;

            case ExpressionType.Index:
                var indexExpression = (IndexExpression)operand;
                if (indexExpression.Object == null)
                {
                    throw new InvalidOperationException("Indexing of null object is invalid");
                }
                if (indexExpression.Object.Type.IsArray && indexExpression.Object.Type.GetArrayRank() == 1)
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, returnDefaultValueLabel, ResultType.ByRefAll, extend, out assigneeType);
                        checkNullReferences = false;
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(Expression.ArrayIndex(indexExpression.Object, indexExpression.Arguments.Single()), context, assigneeIsNullLabel, ResultType.ByRefAll, extend, out assigneeType);
                    }
                    assigneeKind = AssigneeKind.SimpleArray;
                }
                else
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(indexExpression.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(indexExpression.Object, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = indexExpression.Indexer != null ? AssigneeKind.IndexedProperty : AssigneeKind.MultiDimensionalArray;
                }
                break;

            default:
                throw new InvalidOperationException("Unable to assign to an expression of type '" + operand.NodeType + "'");
            }
            if (assigneeType != null && assigneeType.IsValueType)
            {
                using (var temp = context.DeclareLocal(assigneeType))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                }
                assigneeType = assigneeType.MakeByRefType();
            }
            if (assigneeIsNullLabelUsed)
            {
                context.EmitReturnDefaultValue(assigneeType, assigneeIsNullLabel, il.DefineLabel("assigneeIsNotNull"));
            }

            if (checkNullReferences)
            {
                il.Dup();
                il.Brfalse(returnDefaultValueLabel);
                result = true;
            }

            if (assigneeType != null)
            {
                il.Dup();
            }
            object[] arguments = EmitAccess(assigneeKind, operand, context);
            if (!operand.Type.IsNullable())
            {
                if (whatReturn == ResultType.Void)
                {
                    EmitOp(node.NodeType, node.Method, node.Type, context);
                    EmitAssign(assigneeKind, operand, context, arguments);
                }
                else
                {
                    if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign)
                    {
                        using (var assignmentResult = context.DeclareLocal(operand.Type))
                        {
                            il.Stloc(assignmentResult);
                            il.Ldloc(assignmentResult);
                            EmitOp(node.NodeType, node.Method, node.Type, context);
                            EmitAssign(assigneeKind, operand, context, arguments);
                            il.Ldloc(assignmentResult);
                        }
                    }
                    else
                    {
                        EmitOp(node.NodeType, node.Method, node.Type, context);
                        using (var assignmentResult = context.DeclareLocal(operand.Type))
                        {
                            il.Stloc(assignmentResult);
                            EmitAssign(assigneeKind, operand, context, arguments, assignmentResult);
                            il.Ldloc(assignmentResult);
                        }
                    }
                }
            }
            else
            {
                using (var value = context.DeclareLocal(operand.Type))
                {
                    il.Stloc(value);
                    il.Ldloca(value);
                    context.EmitHasValueAccess(operand.Type);
                    var returnNullLabel = il.DefineLabel("returnNull");
                    il.Brfalse(returnNullLabel);
                    il.Ldloca(value);
                    context.EmitValueAccess(operand.Type);
                    Type            argumentType = operand.Type.GetGenericArguments()[0];
                    ConstructorInfo constructor  = operand.Type.GetConstructor(new[] { argumentType });
                    if (whatReturn == ResultType.Void)
                    {
                        EmitOp(node.NodeType, node.Method, argumentType, context);
                        il.Newobj(constructor);
                        EmitAssign(assigneeKind, operand, context, arguments);
                    }
                    else
                    {
                        if (node.NodeType == ExpressionType.PostDecrementAssign || node.NodeType == ExpressionType.PostIncrementAssign)
                        {
                            EmitOp(node.NodeType, node.Method, argumentType, context);
                            il.Newobj(constructor);
                            EmitAssign(assigneeKind, operand, context, arguments);
                            il.Ldloc(value);
                        }
                        else
                        {
                            EmitOp(node.NodeType, node.Method, argumentType, context);
                            il.Newobj(constructor);
                            using (var assignmentResult = context.DeclareLocal(operand.Type))
                            {
                                il.Stloc(assignmentResult);
                                EmitAssign(assigneeKind, operand, context, arguments, assignmentResult);
                                il.Ldloc(assignmentResult);
                            }
                        }
                    }
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);
                    context.MarkLabelAndSurroundWithSP(returnNullLabel);
                    if (assigneeType != null)
                    {
                        il.Pop();
                    }
                    if (whatReturn != ResultType.Void)
                    {
                        il.Ldloc(value);
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                }
            }
            resultType = whatReturn == ResultType.Void ? typeof(void) : operand.Type;
            return(result);
        }
예제 #23
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 exitLabel = il.DefineLabel("exit");

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

            var arr = il.DeclareLocal(typeof(byte[]));

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

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

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

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


            if (prop.PropertyInfo != null)
            {
                il.Ldloc(value);
                il.Call(prop.TypeSizeProperty.Getter);
                il.Stloc(typeSize);
            }
            else
            {
                il.Ldc_I4(prop.TypeSize);
                il.Stloc(typeSize);
            }

            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);
        }
예제 #24
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);
        }
예제 #25
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));
        }
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            Expression left = node.Left;
            Expression right = node.Right;
            Type       leftType, rightType;

            context.EmitLoadArgument(left, false, out leftType);
            context.EmitLoadArgument(right, false, out rightType);
            GroboIL il = context.Il;

            if (!leftType.IsNullable() && !rightType.IsNullable())
            {
                if (node.Method != null)
                {
                    il.Call(node.Method);
                }
                else
                {
                    if (leftType.IsStruct() || rightType.IsStruct())
                    {
                        throw new InvalidOperationException("Cannot compare structs");
                    }
                    il.Ceq();
                    if (node.NodeType == ExpressionType.NotEqual)
                    {
                        il.Ldc_I4(1);
                        il.Xor();
                    }
                }
            }
            else
            {
                var type = leftType;
                if (type != rightType)
                {
                    throw new InvalidOperationException("Cannot compare objects of different types '" + leftType + "' and '" + rightType + "'");
                }
                using (var localLeft = context.DeclareLocal(type))
                    using (var localRight = context.DeclareLocal(type))
                    {
                        il.Stloc(localRight);
                        il.Stloc(localLeft);
                        if (node.Method != null)
                        {
                            il.Ldloca(localLeft);             // stack: [&left]
                            context.EmitHasValueAccess(type); // stack: [left.HasValue]
                            il.Dup();                         // stack: [left.HasValue, left.HasValue]
                            il.Ldloca(localRight);            // stack: [left.HasValue, left.HasValue, &right]
                            context.EmitHasValueAccess(type); // stack: [left.HasValue, left.HasValue, right.HasValue]
                            var notEqualLabel = il.DefineLabel("notEqual");
                            il.Bne_Un(notEqualLabel);         // stack: [left.HasValue]
                            var equalLabel = il.DefineLabel("equal");
                            il.Brfalse(equalLabel);
                            il.Ldloca(localLeft);
                            context.EmitValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitValueAccess(type);
                            il.Call(node.Method);
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(notEqualLabel);
                            il.Pop();
                            il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 0 : 1);
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(equalLabel);
                            il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 1 : 0);
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                        }
                        else
                        {
                            il.Ldloca(localLeft);
                            context.EmitValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitValueAccess(type);
                            var notEqualLabel = il.DefineLabel("notEqual");
                            il.Bne_Un(notEqualLabel);
                            il.Ldloca(localLeft);
                            context.EmitHasValueAccess(type);
                            il.Ldloca(localRight);
                            context.EmitHasValueAccess(type);
                            il.Ceq();
                            var doneLabel = il.DefineLabel("done");
                            il.Br(doneLabel);
                            context.MarkLabelAndSurroundWithSP(notEqualLabel);
                            il.Ldc_I4(0);
                            context.MarkLabelAndSurroundWithSP(doneLabel);
                            if (node.NodeType == ExpressionType.NotEqual)
                            {
                                il.Ldc_I4(1);
                                il.Xor();
                            }
                        }
                    }
            }
            resultType = typeof(bool);
            return(false);
        }
예제 #27
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));
        }
        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);
        }
        private static Type BuildMutatorsTreeCreator(int numberOfGenericParameters)
        {
            var typeBuilder       = module.DefineType("MutatorsTreeCreator_" + numberOfGenericParameters, TypeAttributes.Public | TypeAttributes.Class);
            var genericParameters = typeBuilder.DefineGenericParameters(new[] { "TSource" }.Concat(new int[numberOfGenericParameters - 1].Select((i, index) => "T" + (index + 1))).ToArray());

            var interfaceType = typeof(IMutatorsTreeCreator <>).MakeGenericType(genericParameters.Last());
            var method        = TypeBuilder.GetMethod(interfaceType, typeof(IMutatorsTreeCreator <>).GetMethod(getMutatorsTreeMethodName, BindingFlags.Public | BindingFlags.Instance));
            var methodBuilder = typeBuilder.DefineMethod(getMutatorsTreeMethodName, MethodAttributes.Public | MethodAttributes.Virtual, typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters.Last()),
                                                         new[] { typeof(IDataConfiguratorCollectionFactory), typeof(IConverterCollectionFactory), typeof(MutatorsContext[]), typeof(MutatorsContext[]) });

            using (var il = new GroboIL(methodBuilder))
            {
                il.Ldarg(1);                                                                                                                      // stack: [dataConfiguratorCollectionFactory]
                il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[0]), typeof(IDataConfiguratorCollectionFactory)); // stack: [dataConfiguratorCollectionFactory.Get<TSource> = collection]

                var sourceCollectionIsNullLabel = il.DefineLabel("sourceCollectionIsNull");
                il.Dup();                                // stack: [collection, collection]
                il.Brfalse(sourceCollectionIsNullLabel); // if(collection == null) goto sourceCollectionIsNull; stack: [collection]

                il.Ldarg(3);                             // stack: [collection, mutatorsContexts]
                il.Ldc_I4(0);                            // stack: [collection, mutatorsContexts, 0]
                il.Ldelem(typeof(MutatorsContext));      // stack: [collection, mutatorsContexts[0]]
                il.Ldc_I4(0);                            // stack: [collection, mutatorsContexts[0], 0]
                // todo ich: избавиться от константы
                var collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[0]);
                il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [collection.GetMutatorsTree(mutatorsContexts[0], 0)]

                il.MarkLabel(sourceCollectionIsNullLabel);

                var current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[0]));
                for (var i = 0; i < numberOfGenericParameters - 1; ++i)
                {
                    // First: Migrate tree
                    il.Stloc(current);
                    il.Ldarg(2);                                                                                                                                  // stack: [converterCollectionFactory]
                    il.Call(getConverterCollectionMethod.MakeGenericMethod(genericParameters[i + 1], genericParameters[i]), typeof(IConverterCollectionFactory)); // stack: [converterCollectionFactory.Get<T_i, T_i+1> = converterCollection]
                    il.Dup();                                                                                                                                     // stack: [converterCollection, converterCollection]
                    il.Ldloc(current);                                                                                                                            // stack: [converterCollection, converterCollection, current]
                    il.Ldarg(4);                                                                                                                                  // stack: [converterCollection, converterCollection, current, converterContexts]
                    il.Ldc_I4(i);                                                                                                                                 // stack: [converterCollection, converterCollection, current, converterContexts, i]
                    il.Ldelem(typeof(MutatorsContext));                                                                                                           // stack: [converterCollection, converterCollection, current, converterContexts[i]]
                    // todo ich: избавиться от константы
                    //il.Call(collectionType.GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])]
                    collectionType = typeof(IConverterCollection <,>).MakeGenericType(genericParameters[i + 1], genericParameters[i]);
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("Migrate", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection, converterCollection.Migrate(current, converterContexts[i])]
                    current = il.DeclareLocal(typeof(MutatorsTreeBase <>).MakeGenericType(genericParameters[i + 1]));
                    il.Stloc(current);                                                                                                                                                  // current = converterCollection.Migrate(current, converterContexts[i]); stack: [converterCollection]

                    // Second: Merge with validations tree
                    il.Ldarg(4);                              // stack: [converterCollection, converterContexts]
                    il.Ldc_I4(i);                             // stack: [converterCollection, converterContexts, i]
                    il.Ldelem(typeof(MutatorsContext));       // stack: [converterCollection, converterContexts[i]]
                    il.Ldc_I4(numberOfGenericParameters + i); // stack: [converterCollection, converterContexts[i], n + i]
                    // todo ich: избавиться от константы
                    //il.Call(collectionType.GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree]
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IConverterCollection <,>).GetMethod("GetValidationsTree", BindingFlags.Public | BindingFlags.Instance)), collectionType); // stack: [converterCollection.GetValidationsTree(converterContexts[i], n + i) = validationsTree]
                    il.Ldloc(current);                                                                                                                                                             // stack: [validationsTree, current]
                    //var mutatorsTreeType = typeof(MutatorsTreeBase<>).MakeGenericType(genericParameters[i + 1]);
                    //il.Call(mutatorsTreeType.GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance), mutatorsTreeType); // stack: [validationsTree.Merge(current)]
                    //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current)]
                    il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current)]

                    // Third: Merge with current mutators tree
                    il.Ldarg(1);                                                                                                                          // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory]
                    il.Call(getDataConfiguratorCollectionMethod.MakeGenericMethod(genericParameters[i + 1]), typeof(IDataConfiguratorCollectionFactory)); // stack: [validationsTree.Merge(current), dataConfiguratorCollectionFactory.Get<T_i+1> = collection]

                    var collectionIsNullLabel = il.DefineLabel("collectionIsNull");
                    il.Dup();                           // stack: [validationsTree.Merge(current), collection, collection]
                    il.Brfalse(collectionIsNullLabel);  // if(collection == null) goto collectionIsNull; stack: [validationsTree.Merge(current), collection]

                    il.Ldarg(3);                        // stack: [validationsTree.Merge(current), collection, mutatorsContexts]
                    il.Ldc_I4(i + 1);                   // stack: [validationsTree.Merge(current), collection, mutatorsContexts, i + 1]
                    il.Ldelem(typeof(MutatorsContext)); // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1]]
                    il.Ldc_I4(i + 1);                   // stack: [validationsTree.Merge(current), collection, mutatorsContexts[i + 1], 0]
                    // todo ich: избавиться от константы
                    collectionType = typeof(IDataConfiguratorCollection <>).MakeGenericType(genericParameters[i + 1]);
                    il.Call(TypeBuilder.GetMethod(collectionType, typeof(IDataConfiguratorCollection <>).GetMethod("GetMutatorsTree", new[] { typeof(MutatorsContext), typeof(int) })), collectionType); // stack: [validationsTree.Merge(current), collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)]

                    il.MarkLabel(collectionIsNullLabel);

                    //il.Call(TypeBuilder.GetMethod(mutatorsTreeType, typeof(MutatorsTreeBase<>).GetMethod("Merge", BindingFlags.Public | BindingFlags.Instance)), mutatorsTreeType); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current]
                    il.Call(mergeMethod.MakeGenericMethod(genericParameters[i + 1])); // stack: [validationsTree.Merge(current).Merge(collection.GetMutatorsTree(mutatorsContexts[i + 1], 0)) = current]
                }

                il.Ret();
            }

            typeBuilder.DefineMethodOverride(methodBuilder, method);
            typeBuilder.AddInterfaceImplementation(interfaceType);
            return(typeBuilder.CreateType());
        }
예제 #30
0
파일: Test.cs 프로젝트: qinfengzhu/gremit
        private IQxx BuildSwitch(ModuleBuilder module, string[] keys)
        {
            var numberOfCases = keys.Length;
            var typeBuilder   = module.DefineType("Switch" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public);

            typeBuilder.AddInterfaceImplementation(typeof(IQxx));
            var fields = new FieldInfo[numberOfCases];

            for (var i = 0; i < numberOfCases; ++i)
            {
                fields[i] = typeBuilder.DefineField(keys[i], typeof(int), FieldAttributes.Public);
            }
            var tinyHashtable = Create(keys);
            var n             = tinyHashtable.Length;
            var keysField     = typeBuilder.DefineField("keys", typeof(string[]), FieldAttributes.Public);
            var constructor   = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(string[]) });

            using (var il = new GroboIL(constructor))
            {
                il.Ldarg(0);
                il.Ldarg(1);
                il.Stfld(keysField);
                il.Ret();
            }

            var method = typeBuilder.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { typeof(string), typeof(int) });

            method.DefineParameter(1, ParameterAttributes.In, "key");
            method.DefineParameter(2, ParameterAttributes.In, "value");
            using (var il = new GroboIL(method))
            {
                il.Ldarg(0);
                il.Ldfld(keysField);
                il.Ldarg(1);
                il.Call(HackHelpers.GetMethodDefinition <object>(o => o.GetHashCode()));
                il.Ldc_I4(n);
                il.Rem(true);
                var idx = il.DeclareLocal(typeof(int));
                il.Dup();
                il.Stloc(idx);
                il.Ldelem(typeof(string));
                il.Ldarg(1);
                il.Call(stringEqualityOperator);
                var doneLabel = il.DefineLabel("done");
                il.Brfalse(doneLabel);

                var labels = new GroboIL.Label[n];
                for (var i = 0; i < n; ++i)
                {
                    labels[i] = doneLabel;
                }
                foreach (var key in keys)
                {
                    var index = key.GetHashCode() % n;
                    if (index < 0)
                    {
                        index += n;
                    }
                    var label = il.DefineLabel("set_" + key);
                    labels[index] = label;
                }
                il.Ldloc(idx);
                il.Switch(labels);
                for (var i = 0; i < keys.Length; ++i)
                {
                    var index = keys[i].GetHashCode() % n;
                    if (index < 0)
                    {
                        index += n;
                    }
                    il.MarkLabel(labels[index]);
                    il.Ldarg(0);
                    il.Ldarg(2);
                    il.Stfld(fields[i]);
                    il.Br(doneLabel);
                }
                il.MarkLabel(doneLabel);
                il.Ret();
            }
            typeBuilder.DefineMethodOverride(method, typeof(IQxx).GetMethod("Set"));
            var type = typeBuilder.CreateType();

            return((IQxx)Activator.CreateInstance(type, new object[] { tinyHashtable }));
        }