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); }
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); }
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); }); } }