Exemplo n.º 1
0
        private static void AddGenericPrototypeCalls(MethodDefinition method, MethodDefinition real_method)
        {
            //external types
            Type[] systemFuncs;

            //TODO: find a better way to check for void
            if(method.ReturnType.FullName!="System.Void")
                systemFuncs = new Type[]{ typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>) };
            else
                systemFuncs = new Type[] { typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), typeof(Action<,,,>) };

            var systemFuncClass = method.Module.Import(systemFuncs[method.GenericParameters.Count-1]);
            var systemTypeClass = method.Module.Import(typeof(Type));

            //external call
            var TypeFromHandle = method.Module.Import(systemTypeClass.Resolve().Methods.Single(m => m.Name == "GetTypeFromHandle"));

            //setup Dictionary<Type,object> and it's ContainsKey method
            var dictType = method.Module.Import(typeof(Dictionary<Type, object>));
            var dictContainsKeyMethod = method.Module.Import(dictType.Resolve().Methods.Single(m => m.Name == "ContainsKey"));
            var dictGetItemMethod = method.Module.Import(dictType.Resolve().Methods.Single(m => m.Name == "get_Item"));
            dictContainsKeyMethod.DeclaringType = dictType;
            dictGetItemMethod.DeclaringType = dictType;

            //setup prototype class and delegate for method
            var protoClassType = method.DeclaringType.NestedTypes.Single(m => m.Name == "PrototypeClass");
            var protoDelegateType = protoClassType.NestedTypes.Single(m => m.Name == "Callback_" + ComposeFullMethodName(method));

            //setup fields
            var protoField = method.DeclaringType.Fields.Single(m => m.Name == method.DeclaringType.Name.Replace('`', '_') + "Prototype");
            var staticProtoField = method.DeclaringType.Fields.Single(m => m.Name == "StaticPrototype");
            var dictProperty = protoClassType.Properties.Single(m => m.Name == ComposeFullMethodName(method));

            //setup delegate proto
            var protoDelegate = new GenericInstanceType(protoDelegateType);
            foreach (var param in method.DeclaringType.GenericParameters.Concat(method.GenericParameters))
                protoDelegate.GenericArguments.Add(param);

            //setup invoke method
            var protoInvoke = protoDelegateType.Methods.Single(m => m.Name == "Invoke");

            var il = method.Body.GetILProcessor();

            //this is a place to store instructions, which operands needs to be replaced
            List<Instruction> jmpReplacements = new List<Instruction>();

            var allParamsCount = method.Parameters.Count + (method.IsStatic ? 0 : 1);

            //setup body variables
            method.Body.InitLocals = true;
            method.Body.Variables.Add(new VariableDefinition(systemTypeClass)); //key

            if(method.ReturnType.FullName!="System.Void")
                method.Body.Variables.Add(new VariableDefinition(method.ReturnType)); //data to return

            method.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(bool)))); //for evaluation of conditions

            il.Emit(OpCodes.Nop);

            //making key variable
            systemFuncClass = new GenericInstanceType(systemFuncClass);
            foreach (var param in method.GenericParameters)
                ((GenericInstanceType)systemFuncClass).GenericArguments.Add(param);

            il.Emit(OpCodes.Ldtoken, systemFuncClass);
            il.Emit(OpCodes.Call, TypeFromHandle);
            il.Emit(OpCodes.Stloc_0);

            if (!method.IsStatic && !method.IsConstructor)
            {
                //finding key in dictionary
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldflda, protoField.Instance());
                il.Emit(OpCodes.Call, dictProperty.GetMethod.Instance());
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Callvirt, dictContainsKeyMethod);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brtrue_S, label("KeyNotFound")); //will be replaced

                //if key is found - call proto function
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldflda, protoField.Instance()); // valuetype Cheese.GenericStorage`1/Test<!0> class Cheese.GenericStorage`1<!T>::testSample
                il.Emit(OpCodes.Call, dictProperty.GetMethod.Instance());
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Callvirt, dictGetItemMethod); // instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type[], object>::get_Item(!0)
                il.Emit(OpCodes.Castclass, protoDelegate); // class Cheese.GenericStorage`1/Test/Maker`1<!T, !!L>
                for (int i = 0; i < allParamsCount; i++)
                    il.Emit(OpCodes.Ldarg, i);

                il.Emit(OpCodes.Callvirt, protoInvoke.Instance(method.DeclaringType.GenericParameters, method.GenericParameters)); // instance !1 class Cheese.GenericStorage`1/Test/Maker`1<!T, !!L>::Invoke(class Cheese.GenericStorage`1<!0>, !1)
                il.Emit(OpCodes.Ret);

                il.SetLabel("KeyNotFound");
            }

            //finding key in static prototype dictionary
            il.Emit(OpCodes.Ldsflda, staticProtoField.Instance());
            il.Emit(OpCodes.Call, dictProperty.GetMethod.Instance());
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Callvirt, dictContainsKeyMethod);
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Brtrue_S, label("CallDefault")); //will be replaced

            //if key is found - call proto function
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldsflda, staticProtoField.Instance()); // valuetype Cheese.GenericStorage`1/Test<!0> class Cheese.GenericStorage`1<!T>::testSample
            il.Emit(OpCodes.Call, dictProperty.GetMethod.Instance());
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Callvirt, dictGetItemMethod); // instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type[], object>::get_Item(!0)
            il.Emit(OpCodes.Castclass, protoDelegate); // class Cheese.GenericStorage`1/Test/Maker`1<!T, !!L>
            for (int i = 0; i < allParamsCount; i++)
                il.Emit(OpCodes.Ldarg, i);

            il.Emit(OpCodes.Callvirt, protoInvoke.Instance(method.DeclaringType.GenericParameters, method.GenericParameters)); // instance !1 class Cheese.GenericStorage`1/Test/Maker`1<!T, !!L>::Invoke(class Cheese.GenericStorage`1<!0>, !1)
            il.Emit(OpCodes.Ret);

            //call x-method by default

            il.SetLabel("CallDefault");

            for (int i = 0; i < allParamsCount; i++)
                il.Emit(OpCodes.Ldarg,i);
            il.Emit(OpCodes.Call, real_method.Instance());
            il.Emit(OpCodes.Ret);
        }
Exemplo n.º 2
0
        private static void AddPrototypeCalls(MethodDefinition method, MethodDefinition real_method)
        {
            var staticPrototypeField = method.DeclaringType.Fields.Single(m => m.Name == "StaticPrototype");
            var dynamicPrototypeField = method.DeclaringType.Fields.SingleOrDefault(m => m.Name == method.DeclaringType.Name.Replace('`', '_') + "Prototype");
            var delegateField = method.DeclaringType.NestedTypes.Single(m => m.Name == "PrototypeClass").Fields.Single(m => m.Name == ComposeFullMethodName(method));

            var il = method.Body.GetILProcessor();

            TypeDefinition delegateType = delegateField.FieldType.Resolve();
            var invokeMethod = delegateType.Methods.Single(m => m.Name == "Invoke");
            int allParamsCount = method.Parameters.Count + (method.IsStatic ? 0 : 1); //all params and maybe this

            if (!method.IsStatic && !method.IsConstructor)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldflda, dynamicPrototypeField.Instance());
                il.Emit(OpCodes.Ldfld, delegateField.Instance());
                il.Emit(OpCodes.Brfalse, label("nextCheck"));

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldflda, dynamicPrototypeField.Instance());
                il.Emit(OpCodes.Ldfld, delegateField.Instance());
                for (int i = 0; i < allParamsCount; i++) il.Emit(OpCodes.Ldarg, i);
                il.Emit(OpCodes.Callvirt, invokeMethod.Instance());
                il.Emit(OpCodes.Ret);
            }

            il.SetLabel("nextCheck");

            il.Emit(OpCodes.Ldsflda, staticPrototypeField.Instance());
            il.Emit(OpCodes.Ldfld, delegateField.Instance());
            il.Emit(OpCodes.Brfalse, label("callDefault")); //addres will be replaced

            il.Emit(OpCodes.Ldsflda, staticPrototypeField.Instance());
            il.Emit(OpCodes.Ldfld, delegateField.Instance());
            for (int i = 0; i < allParamsCount; i++) il.Emit(OpCodes.Ldarg, i);
            il.Emit(OpCodes.Callvirt, invokeMethod.Instance());
            il.Emit(OpCodes.Ret);

            il.SetLabel("callDefault");

            for (int i = 0; i < allParamsCount; i++) il.Emit(OpCodes.Ldarg, i);
            il.Emit(OpCodes.Call, real_method.Instance());
            il.Emit(OpCodes.Ret);
        }