/// <summary> /// There are 2 cases: /// 1) Task has no return value. In this case, we emit /// void CheckMethod(Task t) { /// var ae = t.Exception as AggregateException; /// if (ae != null) { ae.Handle(this.CheckException); throw ae; } /// } /// bool CheckException(Exception e) { /// .. check exceptional post /// } /// 2) Task(T) returns a T value /// T CheckMethod(Task t) { /// try { /// var r = t.Result; /// .. check ensures on r .. /// return r; /// } /// catch (AggregateException ae) { /// ae.Handle(this.CheckException); /// throw; /// } /// } /// bool CheckException(Exception e) { /// .. check exceptional post /// } /// </summary> public EmitAsyncClosure(Method from, Rewriter parent) { this.fromMethod = from; this.parent = parent; this.checkMethodId = Identifier.For("CheckPost"); this.checkExceptionMethodId = Identifier.For("CheckException"); this.declaringType = from.DeclaringType; var closureName = HelperMethods.NextUnusedMemberName(declaringType, "<" + from.Name.Name + ">AsyncContractClosure"); this.closureClass = new Class(declaringType.DeclaringModule, declaringType, null, TypeFlags.NestedPrivate, null, Identifier.For(closureName), SystemTypes.Object, null, null); declaringType.Members.Add(this.closureClass); RewriteHelper.TryAddCompilerGeneratedAttribute(this.closureClass); this.dup = new Duplicator(this.declaringType.DeclaringModule, this.declaringType); var taskType = from.ReturnType; var taskArgs = taskType.TemplateArguments == null ? 0 : taskType.TemplateArguments.Count; this.AggregateExceptionType = new Cache<TypeNode>(() => HelperMethods.FindType(parent.assemblyBeingRewritten, StandardIds.System, Identifier.For("AggregateException"))); this.Func2Type = new Cache<TypeNode>(() => HelperMethods.FindType(SystemTypes.SystemAssembly, StandardIds.System, Identifier.For("Func`2"))); if (from.IsGeneric) { this.closureClass.TemplateParameters = new TypeNodeList(); var parentCount = this.declaringType.ConsolidatedTemplateParameters == null ? 0 : this.declaringType.ConsolidatedTemplateParameters.Count; for (int i = 0; i < from.TemplateParameters.Count; i++) { var tp = HelperMethods.NewEqualTypeParameter(dup, (ITypeParameter)from.TemplateParameters[i], this.closureClass, parentCount + i); this.closureClass.TemplateParameters.Add(tp); } this.closureClass.IsGeneric = true; this.closureClass.EnsureMangledName(); this.forwarder = new Specializer(this.declaringType.DeclaringModule, from.TemplateParameters, this.closureClass.TemplateParameters); this.forwarder.VisitTypeParameterList(this.closureClass.TemplateParameters); taskType = this.forwarder.VisitTypeReference(taskType); } else { this.closureClassInstance = this.closureClass; } var taskTemplate = HelperMethods.Unspecialize(taskType); var continueWithCandidates = taskTemplate.GetMembersNamed(Identifier.For("ContinueWith")); Method continueWithMethod = null; for (int i = 0; i < continueWithCandidates.Count; i++) { var cand = continueWithCandidates[i] as Method; if (cand == null) continue; if (taskArgs == 0) { if (cand.IsGeneric) continue; if (cand.ParameterCount != 1) continue; var p = cand.Parameters[0]; var ptype = p.Type; var ptypeTemplate = ptype; while (ptypeTemplate.Template != null) { ptypeTemplate = ptypeTemplate.Template; } if (ptypeTemplate.Name.Name != "Action`1") continue; continueWithMethod = cand; break; } else { if (!cand.IsGeneric) continue; if (cand.TemplateParameters.Count != 1) continue; if (cand.ParameterCount != 1) continue; var p = cand.Parameters[0]; var ptype = p.Type; var ptypeTemplate = ptype; while (ptypeTemplate.Template != null) { ptypeTemplate = ptypeTemplate.Template; } if (ptypeTemplate.Name.Name != "Func`2") continue; // now create instance, first of task var taskInstance = taskTemplate.GetTemplateInstance(this.closureClass.DeclaringModule, taskType.TemplateArguments[0]); var candMethod = taskInstance.GetMembersNamed(Identifier.For("ContinueWith"))[i] as Method; continueWithMethod = candMethod.GetTemplateInstance(null, taskType.TemplateArguments[0]); break; } } if (continueWithMethod != null) { this.continuewithMethod = continueWithMethod; EmitCheckMethod(taskType, taskArgs == 1); var ctor = new InstanceInitializer(this.closureClass, null, null, null); this.constructor = ctor; ctor.CallingConvention = CallingConventionFlags.HasThis; ctor.Flags |= MethodFlags.Public | MethodFlags.HideBySig; ctor.Body = new Block(new StatementList( new ExpressionStatement(new MethodCall(new MemberBinding(ctor.ThisParameter, SystemTypes.Object.GetConstructor()), new ExpressionList())), new Return() )); this.closureClass.Members.Add(ctor); } // now that we added the ctor and the check method, let's instantiate the closure class if necessary if (this.closureClassInstance == null) { var consArgs = new TypeNodeList(); var args = new TypeNodeList(); var parentCount = this.closureClass.DeclaringType.ConsolidatedTemplateParameters == null ? 0 : this.closureClass.DeclaringType.ConsolidatedTemplateParameters.Count; for (int i = 0; i < parentCount; i++) { consArgs.Add(this.closureClass.DeclaringType.ConsolidatedTemplateParameters[i]); } var methodCount = from.TemplateParameters == null ? 0: from.TemplateParameters.Count; for (int i = 0; i < methodCount; i++) { consArgs.Add(from.TemplateParameters[i]); args.Add(from.TemplateParameters[i]); } this.closureClassInstance = (Class)this.closureClass.GetConsolidatedTemplateInstance(this.parent.assemblyBeingRewritten, closureClass.DeclaringType, closureClass.DeclaringType, args, consArgs); } // create closure initializer for context method this.ClosureLocal = new Local(this.ClosureClass); this.ClosureInitializer = new Block(new StatementList()); this.ClosureInitializer.Statements.Add(new AssignmentStatement(this.ClosureLocal, new Construct(new MemberBinding(null, this.Ctor), new ExpressionList()))); }
public RewriteAssertAssumeAndCallSiteRequires(Dictionary<Method, bool> replacementMethods, RuntimeContractMethods runtimeContracts, RuntimeContractEmitFlags emitFlags, Rewriter parent, Method containingMethod) { this.methodTable = replacementMethods; this.runtimeContracts = runtimeContracts; this.emitFlags = emitFlags; this.parent = parent; this.containingMethod = containingMethod; }
public EmitAsyncClosure(Method from, Rewriter rewriter) { Contract.Requires(from != null); Contract.Requires(from.DeclaringType != null); Contract.Requires(rewriter != null); if (TaskExtensionsTypeNode == null) { throw new InvalidOperationException( "Can't generate async closure because System.Threading.Tasks.TaskExceptions class is unavailable."); } this.rewriter = rewriter; this.declaringType = from.DeclaringType; var closureName = HelperMethods.NextUnusedMemberName(declaringType, "<" + from.Name.Name + ">AsyncContractClosure"); this.closureClass = new Class( declaringModule: declaringType.DeclaringModule, declaringType: declaringType, attributes: null, flags: TypeFlags.NestedPrivate, Namespace: null, name: Identifier.For(closureName), baseClass: SystemTypes.Object, interfaces: null, members: null); declaringType.Members.Add(this.closureClass); RewriteHelper.TryAddCompilerGeneratedAttribute(this.closureClass); var taskType = from.ReturnType; this.aggregateExceptionType = new Cache<TypeNode>(() => HelperMethods.FindType(rewriter.AssemblyBeingRewritten, StandardIds.System, Identifier.For("AggregateException"))); this.func2Type = new Cache<TypeNode>(() => HelperMethods.FindType(SystemTypes.SystemAssembly, StandardIds.System, Identifier.For("Func`2"))); // Should distinguish between generic enclosing method and non-generic method in enclosing type. // In both cases generated closure should be generic. var enclosingTemplateParameters = GetGenericTypesFrom(from); if (!enclosingTemplateParameters.IsNullOrEmpty()) { this.closureClass.TemplateParameters = CreateTemplateParameters(closureClass, enclosingTemplateParameters, declaringType); this.closureClass.IsGeneric = true; this.closureClass.EnsureMangledName(); this.forwarder = new Specializer( targetModule: this.declaringType.DeclaringModule, pars: enclosingTemplateParameters, args: this.closureClass.TemplateParameters); this.forwarder.VisitTypeParameterList(this.closureClass.TemplateParameters); taskType = this.forwarder.VisitTypeReference(taskType); for (int i = 0; i < enclosingTemplateParameters.Count; i++) { this.genericTypeMapper.AddMapping(enclosingTemplateParameters[i], closureClass.TemplateParameters[i]); } } else { this.closureClassInstance = this.closureClass; } this.checkMethodTaskType = taskType; // Emiting CheckPost method declaration EmitCheckPostMethodCore(checkMethodTaskType); // Generate closure constructor. // Constructor should be generated AFTER visiting type parameters in // the previous block of code. Otherwise current class would not have // appropriate number of generic arguments! var ctor = CreateConstructor(closureClass); closureClass.Members.Add(ctor); // Now that we added the ctor and the check method, let's instantiate the closure class if necessary if (this.closureClassInstance == null) { var consArgs = new TypeNodeList(); var args = new TypeNodeList(); var parentCount = this.closureClass.DeclaringType.ConsolidatedTemplateParameters == null ? 0 : this.closureClass.DeclaringType.ConsolidatedTemplateParameters.Count; for (int i = 0; i < parentCount; i++) { consArgs.Add(this.closureClass.DeclaringType.ConsolidatedTemplateParameters[i]); } if (!enclosingTemplateParameters.IsNullOrEmpty()) { for (int i = 0; i < enclosingTemplateParameters.Count; i++) { consArgs.Add(enclosingTemplateParameters[i]); args.Add(enclosingTemplateParameters[i]); } } this.closureClassInstance = (Class) this.closureClass.GetConsolidatedTemplateInstance(this.rewriter.AssemblyBeingRewritten, closureClass.DeclaringType, closureClass.DeclaringType, args, consArgs); } // create closure initializer for context method this.closureLocal = new Local(this.ClosureClass); this.ClosureInitializer = new Block(new StatementList()); // Generate constructor call that initializes closure instance this.ClosureInitializer.Statements.Add( new AssignmentStatement( this.closureLocal, new Construct(new MemberBinding(null, this.Ctor), new ExpressionList()))); }