private void SetupReturnPoints()
        {
            if (_returnPoint != null || _originalReturnPoint != null)
            {
                throw new InvalidOperationException("Something went wrong");
            }

            SetupReturnVariable();

            var processor = ILProcessorFactory.GetOrCreateProcessor(TargetMethod.Body);

            var singleReturnPoint = processor.Create(OpCodes.Nop);

            _originalReturnPoint = new PointCut(processor, SetupSingleReturnPoint(processor.Create(OpCodes.Br, singleReturnPoint), MethodResultVariable)); //todo:: optimize
            processor.SafeAppend(singleReturnPoint);

            if (!TargetMethod.ReturnType.IsTypeOf(typeof(void)))
            {
                _returnPoint = new PointCut(processor, processor.SafeAppend(processor.CreateOptimized(OpCodes.Ldloc, MethodResultVariable.Index)));
                processor.SafeAppend(processor.Create(OpCodes.Ret));
            }
            else
            {
                _returnPoint = new PointCut(processor, processor.SafeAppend(processor.Create(OpCodes.Ret)));
            }
        }
        protected PointCut FindBaseClassCtorCall()
        {
            var md   = TargetMethod;
            var proc = ILProcessorFactory.GetOrCreateProcessor(md.Body);

            if (!md.IsConstructor)
            {
                throw new Exception(md.ToString() + " is not ctor.");
            }

            if (md.DeclaringType.IsValueType)
            {
                return(new PointCut(proc, md.Body.Instructions.First()));
            }

            var point = md.Body.Instructions.FirstOrDefault(
                i => i != null && i.OpCode == OpCodes.Call && i.Operand is MethodReference &&
                ((MethodReference)i.Operand).Resolve().IsConstructor &&
                (((MethodReference)i.Operand).DeclaringType.IsTypeOf(md.DeclaringType.BaseType) ||
                 ((MethodReference)i.Operand).DeclaringType.IsTypeOf(md.DeclaringType)));

            if (point == null)
            {
                throw new Exception("Cannot find base class ctor call");
            }

            return(new PointCut(proc, point.Next));
        }
        protected Instruction SetupSingleReturnPoint(Instruction suggestedSingleReturnPoint, VariableReference resultVar)
        {
            var proc = ILProcessorFactory.GetOrCreateProcessor(TargetMethod.Body);

            var rets = proc.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret).ToList();

            if (rets.Count == 1)
            {
                if (!TargetMethod.ReturnType.IsTypeOf(typeof(void)))
                {
                    proc.SafeInsertBefore(rets.First(), proc.CreateOptimized(OpCodes.Stloc, resultVar.Index));
                }

                return(proc.SafeReplace(rets.First(), suggestedSingleReturnPoint));
            }

            foreach (var i in rets)
            {
                if (!TargetMethod.ReturnType.IsTypeOf(typeof(void)))
                {
                    proc.SafeInsertBefore(i, proc.CreateOptimized(OpCodes.Stloc, resultVar.Index));
                }

                proc.SafeReplace(i, proc.Create(OpCodes.Br, suggestedSingleReturnPoint)); //todo:: optimize
            }

            proc.SafeAppend(suggestedSingleReturnPoint);

            return(suggestedSingleReturnPoint);
        }
        public TargetMethodContext CreateMethod(string name, MethodAttributes attrs, TypeReference returnType)
        {
            var method    = new MethodDefinition(name, attrs, TypeDefinition.Module.Import(returnType));
            var processor = ILProcessorFactory.GetOrCreateProcessor(method.Body);

            processor.Append(processor.Create(OpCodes.Nop));
            processor.Append(processor.Create(OpCodes.Ret));
            TypeDefinition.Methods.Add(method);
            return(MethodContextFactory.GetOrCreateContext(method));
        }
        protected PointCut GetMethodOriginalEntryPoint()
        {
            var processor = ILProcessorFactory.GetOrCreateProcessor(TargetMethod.Body);

            if (TargetMethod.Body.Instructions.Count == 1) //if code is optimized
            {
                processor.InsertBefore(TargetMethod.Body.Instructions.First(), processor.Create(OpCodes.Nop));
            }

            return(new PointCut(processor, TargetMethod.Body.Instructions.First()));
        }
        public PointCut CreateNewAroundPoint()
        {
            if (_topWrapperCallSite == null)
            {
                SetupAroundInfrastructure();
            }

            var newWrapper = CopyMethodDefinition(AroundWrappedMethodPrefix + _wrapperNo + "_" + TopWrapper.Name,
                                                  TargetMethod.Attributes,
                                                  TypeSystem.Object);

            newWrapper.NoInlining = false;

            MarkDebuggerHidden(newWrapper);
            MarkCompilerGenerated(newWrapper);

            TargetMethod.DeclaringType.Methods.Add(newWrapper);

            var argsParam = new ParameterDefinition(TypeSystem.ObjectArray);

            newWrapper.Parameters.Add(argsParam);

            var tempPc = PointCut.FromEmptyBody(newWrapper.Body, OpCodes.Ret);

            //if (_topWrapper.ReturnType == TypeSystem.Void)
            //    tempPc.CreateVariableFromStack(TypeSystem.Object);
            //else if (_topWrapper.ReturnType.IsValueType)
            //    tempPc.InsertBefore(tempPc.CreateInstruction(OpCodes.Box, TargetMethod.Module.Import(_topWrapper.ReturnType)));

            var newWapperPoint = new WrapperPointCut(argsParam, _lastWrapper, ILProcessorFactory.GetOrCreateProcessor(newWrapper.Body), newWrapper.Body.Instructions.First());

            _lastWrapper = newWrapper;
            _wrapperNo++;

            //substiture top wrapper's call
            _topWrapperCallSite.InjectionPoint.Operand = newWrapper;

            return(newWapperPoint);
        }
Exemple #7
0
        private TypeDefinition GetOrCreateHelperClass()
        {
            var helperClass = TargetMethod.DeclaringType.NestedTypes.FirstOrDefault(nc => nc.Name == HelperClassName);

            if (helperClass == null)
            {
                helperClass = new TypeDefinition(null, HelperClassName, TypeAttributes.Sealed | TypeAttributes.NotPublic | TypeAttributes.NestedPrivate, TargetMethod.Module.TypeSystem.Object);
                MarkCompilerGenerated(helperClass);
                TargetMethod.DeclaringType.NestedTypes.Add(helperClass);

                var ctor = new MethodDefinition(
                    ".ctor",
                    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                    TargetMethod.Module.TypeSystem.Void);

                helperClass.Methods.Add(ctor);

                var ctorProc = ILProcessorFactory.GetOrCreateProcessor(ctor.Body);
                ctorProc.Append(ctorProc.Create(OpCodes.Ldarg_0));
                ctorProc.Append(ctorProc.Create(OpCodes.Call, TargetMethod.Module.Import(TargetMethod.Module.TypeSystem.Object.Resolve().Methods.First(m => m.IsConstructor && !m.IsStatic))));
                ctorProc.Append(ctorProc.Create(OpCodes.Ret));
            }

            _helperThisRefFiled = helperClass.Fields.FirstOrDefault(f => f.Name == HelperClassOriginRefName);
            if (_helperThisRefFiled == null)
            {
                _helperThisRefFiled = new FieldDefinition(HelperClassOriginRefName, FieldAttributes.Public, TargetMethod.DeclaringType);
                helperClass.Fields.Add(_helperThisRefFiled);
            }

            _helperArgumentsFiled = helperClass.Fields.FirstOrDefault(f => f.Name == HelperClassArgumentsRefName);
            if (_helperArgumentsFiled == null)
            {
                _helperArgumentsFiled = new FieldDefinition(HelperClassArgumentsRefName, FieldAttributes.Public, new ArrayType(TargetMethod.Module.TypeSystem.Object));
                helperClass.Fields.Add(_helperArgumentsFiled);
            }

            return(helperClass);
        }
Exemple #8
0
        private void SetupTaskContinuation()
        {
            if (_returnPoint != null || _originalReturnPoint != null)
            {
                throw new InvalidOperationException("Something went wrong");
            }

            var helper = GetOrCreateHelperClass();

            var continuation = new MethodDefinition(
                string.Format(ContinuationMethodName, TargetMethod.Name),
                MethodAttributes.Assembly,
                TargetMethod.Module.TypeSystem.Void);

            helper.Methods.Add(continuation);

            var tcsType       = ModuleContext.TypeSystem.TaskCompletionGeneric.MakeGenericType(_completionResultType);
            var taskTypedType = continuation.Module.Import(_hasResult ? TargetMethod.ReturnType : ModuleContext.TypeSystem.Task);

            var taskParameter = new ParameterDefinition(null, ParameterAttributes.None, taskTypedType);

            continuation.Parameters.Add(taskParameter);

            var tcsField = new FieldDefinition(string.Format(ContinuationFieldName, TargetMethod.Name), FieldAttributes.Public, tcsType);

            helper.Fields.Add(tcsField);

            var proc = ILProcessorFactory.GetOrCreateProcessor(continuation.Body);
            var ret  = proc.Create(OpCodes.Ret);

            proc.Append(ret);

            var pointcut = new PointCut(proc, ret);

            pointcut.LoadParameterOntoStack(taskParameter);
            pointcut.InjectMethodCall(ModuleContext.TypeSystem.Task.Resolve().Properties.First(p => p.Name == "IsCompleted").GetMethod, new object[] { });

            pointcut.TestValueOnStack(true,
                                      doIfTrue: pc =>
            {
                pc.LoadParameterOntoStack(taskParameter);
                pc.InjectMethodCall(ModuleContext.TypeSystem.Task.Resolve().Properties.First(p => p.Name == "IsFaulted").GetMethod, new object[] { });
                pc.TestValueOnStack(false,
                                    doIfTrue: pct =>
                {
                    if (_hasResult)
                    {
                        _resultVar = pct.CreateVariable(_completionResultType,
                                                        loadData: c =>
                        {
                            c.LoadParameterOntoStack(taskParameter);
                            c.InjectMethodCall(taskTypedType.Resolve().Properties.First(p => p.Name == "Result").GetMethod.MakeGeneric(taskTypedType), new object[] { });
                        });
                    }

                    var syncReturnPc = pct.InsertBefore(pct.CreateInstruction(OpCodes.Nop));
                    _returnPoint     = new AsyncPointCut(_helperThisRefFiled, _helperArgumentsFiled, proc, syncReturnPc.InjectionPoint);

                    var setresultMethod = tcsType.Resolve().Methods.First(m => m.Name == "SetResult").MakeGeneric(tcsType);

                    pct.LoadSelfOntoStack();
                    pct.LoadField(tcsField);
                    pct.InjectMethodCall(setresultMethod, new object[] { _resultVar ?? Markers.DefaultMarker });
                });
            },
                                      doIfFalse: pc =>
            {
                var setresultMethod = tcsType.Resolve().Methods.First(m => m.Name == "SetResult").MakeGeneric(tcsType);

                pc.LoadSelfOntoStack();
                pc.LoadField(tcsField);
                pc.InjectMethodCall(setresultMethod, new object[] { Markers.DefaultMarker });
            });

            VariableDefinition taskResult = null;

            if (_isVoid)
            {
                taskResult = OriginalEntryPoint.CreateVariable(ModuleContext.TypeSystem.Task);
            }
            else
            {
                taskResult = OriginalEntryPoint.CreateVariable(TargetMethod.ReturnType);
            }

            var processor = ILProcessorFactory.GetOrCreateProcessor(TargetMethod.Body);

            var singleReturnPoint = processor.Create(OpCodes.Nop);

            _originalReturnPoint = new PointCut(processor, SetupSingleReturnPoint(processor.Create(OpCodes.Br, singleReturnPoint), taskResult)); //todo:: optimize

            if (_isVoid)
            {
                AsyncVoidRewriter.Rewrite(_originalReturnPoint, TargetMethod, taskResult);
            }

            processor.SafeAppend(singleReturnPoint);

            PointCut continuationPoint = null;

            if (!_isVoid)
            {
                continuationPoint = new PointCut(processor, processor.SafeAppend(processor.CreateOptimized(OpCodes.Ldloc, taskResult.Index)));
                processor.SafeAppend(processor.Create(OpCodes.Ret));
            }
            else
            {
                continuationPoint = new PointCut(processor, processor.SafeAppend(processor.Create(OpCodes.Ret)));
            }

            // var tcs = new TaskContinuationSource<TResult>();
            var tcsctor = tcsType.Resolve().Methods.First(m => m.IsConstructor && !m.IsStatic).MakeGeneric(tcsType);
            var tcsVar  = continuationPoint.CreateVariable(tcsType, null, c => c.InjectMethodCall(tcsctor));

            // var helper = new Helper();
            var helperVar = continuationPoint.CreateVariable(helper, null, c => c.InjectMethodCall(helper.Methods.First(m => m.IsConstructor && !m.IsStatic)));

            // var args = new object[] { param1, param2 ... };
            var argsvar = continuationPoint.CreateVariable(new ArrayType(TargetMethod.Module.TypeSystem.Object), null, c => c.LoadCallArgument(TargetMethod.Parameters.ToArray(), new ArrayType(TargetMethod.Module.TypeSystem.Object)));

            //helper.this_ref = this
            continuationPoint.LoadVariable(helperVar);
            continuationPoint.SetField(_helperThisRefFiled, c => c.LoadSelfOntoStack());

            // helper.args = args
            continuationPoint.LoadVariable(helperVar);
            continuationPoint.SetField(_helperArgumentsFiled, c => c.LoadVariable(argsvar));

            // helper.continuationSource = tcs
            continuationPoint.LoadVariable(helperVar);
            continuationPoint.SetField(tcsField, c => c.LoadVariable(tcsVar));

            // task.ContinueWith(new Action<TResult>(helper.Continuation))
            continuationPoint.LoadVariable(helperVar);
            continuationPoint.InsertBefore(continuationPoint.CreateInstruction(OpCodes.Ldftn, continuation));

            var actionTr       = continuation.Module.Import(ModuleContext.TypeSystem.ActionGeneric.MakeGenericType(taskTypedType));
            var contActionCtor = continuation.Module.Import(actionTr.Resolve().Methods.First(m => m.IsConstructor && !m.IsStatic))
                                 .MakeGeneric(actionTr);

            var actionVar = continuationPoint.CreateVariable(actionTr, null, c => c.InsertBefore(continuationPoint.CreateInstruction(OpCodes.Newobj, (MethodReference)c.CreateMemberReference(contActionCtor))));

            MethodReference contWithMethod = continuation.Module.Import(taskTypedType.Resolve().Methods.First(m => m.Name == "ContinueWith" && m.Parameters.Count == 1));

            if (_hasResult)
            {
                contWithMethod = contWithMethod.MakeGeneric(taskTypedType);
            }

            continuationPoint.LoadVariable(taskResult);
            continuationPoint.InjectMethodCall(contWithMethod, new object[] { actionVar });
            continuationPoint.InsertBefore(continuationPoint.CreateInstruction(OpCodes.Pop));

            // task = tcs.Task
            if (!_isVoid)
            {
                var getTask = continuation.Module.Import(tcsType.Resolve().Properties.First(p => p.Name == "Task").GetMethod)
                              .MakeGeneric(tcsType);

                continuationPoint.SetVariable(taskResult,
                                              c =>
                {
                    c.LoadVariable(tcsVar);
                    c.InjectMethodCall(getTask);
                });
            }
        }