Beispiel #1
0
        /// <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())));
        }
Beispiel #2
0
 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())));
        }