private void ProcessClosureClass(Method method, TypeNode closure, bool isAsync)
        {
            Contract.Requires(method != null);
            Contract.Requires(closure != null);

            Method movenext = closure.GetMethod(StandardIds.MoveNext);

            if (movenext == null) return;

            movenext.IsAsync = isAsync;
            if (movenext.Body == null) return;

            if (movenext.Body.Statements == null) return;

            SourceContext defaultSourceContext;
            Block contractInitializerBlock = new Block(new StatementList());

            HelperMethods.StackDepthTracker dupStackTracker = new HelperMethods.StackDepthTracker();
            AssumeBlock originalContractPosition;

            StatementList contractClump = GetContractClumpFromMoveNext(method, movenext, contractNodes,
                contractInitializerBlock.Statements, out defaultSourceContext, ref dupStackTracker,
                out originalContractPosition);

            if (contractClump != null)
            {
                // Look for bad stuff

                BadStuff(method, contractClump, defaultSourceContext);

                // Make sure any locals in the contracts are disjoint from the locals in the rest of the body

                // can use the same one throughout
                GatherLocals gatherLocals = new GatherLocals();

                // Make sure that the entire contract section is closed.
                if (!CheckClump(movenext, gatherLocals, currentMethodSourceContext, new Block(contractClump)))
                {
                    movenext.ClearBody();
                    return;

                }
                // Checking that had the side effect of populating the hashtable, but now each contract will be individually visited.
                // That process needs to start with a fresh table.
                gatherLocals.Locals = new TrivialHashtable();
                RequiresList Preconditions = new RequiresList();
                EnsuresList Postconditions = new EnsuresList();
                RequiresList Validations = new RequiresList();
                EnsuresList modelPostconditions = new EnsuresList();
                EnsuresList asyncPostconditions = null;

                // REVIEW: What should we do with the Validations in this case? Should we map them to the enumerator method? Maybe not, since without
                // rewriting this won't happen.
                if (!ExtractFromClump(contractClump, movenext, gatherLocals, Preconditions, Postconditions, Validations,
                    modelPostconditions, defaultSourceContext, method, contractInitializerBlock, ref dupStackTracker))
                {
                    movenext.ClearBody();
                    return;
                }

                if (isAsync)
                {
                    asyncPostconditions = SplitAsyncEnsures(ref Postconditions, method);
                }

                try
                {
                    // Next is to attach the preconditions to method (instead of movenext)
                    // To do so, we have to duplicate the expressions and statements in Precondition, Postcondition and contractInitializerBlock
                    Duplicator dup = new Duplicator(closure.DeclaringModule, method.DeclaringType);

                    var origPreconditions = Preconditions;
                    var origValidations = Validations;
                    var origcontractInitializerBlock = contractInitializerBlock;

                    Preconditions = dup.VisitRequiresList(Preconditions);
                    Postconditions = dup.VisitEnsuresList(Postconditions);
                    Validations = dup.VisitRequiresList(Validations);
                    contractInitializerBlock = dup.VisitBlock(contractInitializerBlock);
                    asyncPostconditions = dup.VisitEnsuresList(asyncPostconditions);

                    var mapClosureExpToOriginal = BuildMappingFromClosureToOriginal(closure, movenext, method);

                    Preconditions = mapClosureExpToOriginal.Apply(Preconditions);
                    Postconditions = mapClosureExpToOriginal.Apply(Postconditions);
                    Validations = mapClosureExpToOriginal.Apply(Validations);
                    contractInitializerBlock = mapClosureExpToOriginal.Apply(contractInitializerBlock);
                    asyncPostconditions = mapClosureExpToOriginal.Apply(asyncPostconditions);

                    //MemberList members = FindClosureMembersInContract(closure, movenext);
                    // MakeClosureAccessibleToOriginalMethod(closure, members);
                    if (method.Contract == null)
                        method.Contract = new MethodContract(method);

                    method.Contract.Requires = Preconditions;
                    method.Contract.Validations = Validations;

                    // Postconditions are sanity checked here, because Result<T> must be compared against the
                    // return type of the original method. It is most conveniently done after the type substitution. 
                    // TODO: refactor the checking part altogether out of ExtractFromClump. 
                    method.Contract.Ensures = Postconditions;
                    method.Contract.ModelEnsures = modelPostconditions;
                    method.Contract.ContractInitializer = contractInitializerBlock;
                    method.Contract.AsyncEnsures = asyncPostconditions;

                    // Following replacement causes some weird issues for complex preconditions (like x != null && x.Length > 0)
                    // when CCRewriter is used with /publicsurface or Preconditions only.
                    // This fix could be temporal and proper fix would be applied in the future.
                    // After discussion this issue with original CC authors (Mike Barnett and Francesco Logozzo),
                    // we decided that this fix is safe and lack of Assume statement in the MoveNext method will not affect
                    // customers (neither CCRewriter customers nor CCCheck customers).
                    // If this assumption would not be true in the future, proper fix should be applied.
                    // put requires as assumes into movenext method at original position
                    // ReplaceRequiresWithAssumeInMoveNext(origPreconditions, originalContractPosition);

                    // no postPreamble to initialize, as method is not a ctor
                }
                finally
                {
                    // this is done in caller!!!

                    //// normalize contract by forcing IsPure to look at attributes and removing contract it is empty
                    //var contract = method.Contract;
                    //var isPure = contract.IsPure;

                    //if (!isPure && contract.RequiresCount == 0 && contract.EnsuresCount == 0 && contract.ModelEnsuresCount == 0 && contract.ValidationsCount == 0 && contract.AsyncEnsuresCount == 0)
                    //{
                    //  method.Contract = null;
                    //} else
                    //{
                    //  // turn helper method calls to Result, OldValue, ValueAtReturn into proper AST nodes.
                    //  this.extractionFinalizer.VisitMethodContract(method.Contract);
                    //}
                }
            }
        }
Example #2
0
    private Method CreateWrapperMethod(bool virtcall, TypeNode virtcallConstraint, Method templateMethod, TypeNode templateType, TypeNode wrapperType, Method methodWithContract, Method instanceMethod, SourceContext callingContext)
    {
      bool isProtected = IsProtected(templateMethod);
      Identifier name = templateMethod.Name;
      if (virtcall) {
        if (virtcallConstraint != null) {
          name = Identifier.For("CV$" + name.Name);
        }
        else {
          name = Identifier.For("V$" + name.Name);
        }
      }
      else {
        name = Identifier.For("NV$" + name.Name);
      }
      Duplicator dup = new Duplicator(this.assemblyBeingRewritten, wrapperType);
      TypeNodeList typeParameters = null;
      TypeNodeList typeParameterFormals = new TypeNodeList();
      TypeNodeList typeParameterActuals = new TypeNodeList();

      if (templateMethod.TemplateParameters != null) {
        dup.FindTypesToBeDuplicated(templateMethod.TemplateParameters);
        typeParameters = dup.VisitTypeParameterList(templateMethod.TemplateParameters);
        for (int i = 0; i < typeParameters.Count; i++) {
          typeParameterFormals.Add(typeParameters[i]);
          typeParameterActuals.Add(templateMethod.TemplateParameters[i]);
        }
      }
      ITypeParameter constraintTypeParam = null;
      if (virtcallConstraint != null) {
        if (typeParameters == null) { typeParameters = new TypeNodeList(); }
        var constraint = templateMethod.DeclaringType;
        var classConstraint = constraint as Class;
        if (classConstraint != null) {
          var classParam = new MethodClassParameter();
          classParam.BaseClass = classConstraint;
          classParam.Name = Identifier.For("TC");
          classParam.DeclaringType = wrapperType;
          typeParameters.Add(classParam);
          constraintTypeParam = classParam;
        }
        else {
          var mtp = new MethodTypeParameter();
          Interface intf = constraint as Interface;
          if (intf != null) {
            mtp.Interfaces.Add(intf);
          }
          mtp.Name = Identifier.For("TC");
          mtp.DeclaringType = wrapperType;
          typeParameters.Add(mtp);
          constraintTypeParam = mtp;
        }
      }
      var consolidatedTemplateTypeParameters = templateType.ConsolidatedTemplateParameters;
      if (consolidatedTemplateTypeParameters != null && consolidatedTemplateTypeParameters.Count > 0) {
        var consolidatedWrapperTypeParameters = wrapperType.ConsolidatedTemplateParameters;
        for (int i = 0; i < consolidatedTemplateTypeParameters.Count; i++) {
          typeParameterFormals.Add(consolidatedWrapperTypeParameters[i]);
          typeParameterActuals.Add(consolidatedTemplateTypeParameters[i]);
        }
      }
      Specializer spec = null;
      if (typeParameterActuals.Count > 0) {
        spec = new Specializer(this.assemblyBeingRewritten, typeParameterActuals, typeParameterFormals);
      }
      var parameters = new ParameterList();
      var asTypeConstraintTypeParam = constraintTypeParam as TypeNode;

      if (!isProtected && !templateMethod.IsStatic) {
        TypeNode thisType = GetThisTypeInstance(templateType, wrapperType, asTypeConstraintTypeParam);
        parameters.Add(new Parameter(Identifier.For("@this"), thisType));
      }
      for (int i = 0; i < templateMethod.Parameters.Count; i++) {
        parameters.Add((Parameter)dup.VisitParameter(templateMethod.Parameters[i]));
      }
      var retType = dup.VisitTypeReference(templateMethod.ReturnType);
      if (spec != null) {
        parameters = spec.VisitParameterList(parameters);
        retType = spec.VisitTypeReference(retType);
      }

      var wrapperMethod = new Method(wrapperType, null, name, parameters, retType, null);
      RewriteHelper.TryAddCompilerGeneratedAttribute(wrapperMethod);

      if (isProtected) {
        wrapperMethod.Flags = templateMethod.Flags & ~MethodFlags.Abstract;
        wrapperMethod.CallingConvention = templateMethod.CallingConvention;
      }
      else {
        wrapperMethod.Flags |= MethodFlags.Static | MethodFlags.Assembly;
      }
      if (constraintTypeParam != null) {
        constraintTypeParam.DeclaringMember = wrapperMethod;
      }
      if (typeParameters != null) {
        if (spec != null) {
          typeParameters = spec.VisitTypeParameterList(typeParameters);
        }
        wrapperMethod.IsGeneric = true;
        wrapperMethod.TemplateParameters = typeParameters;
      }

      // create body
      var sl = new StatementList();
      Block b = new Block(sl);

      // insert requires
      AddRequiresToWrapperMethod(wrapperMethod, b, methodWithContract);

      // create original call
      var targetType = templateType;
      if (isProtected)
      {
        // need to use base chain instantiation of target type.
        targetType = instanceMethod.DeclaringType;
      }
      else
      {
        if (targetType.ConsolidatedTemplateParameters != null && targetType.ConsolidatedTemplateParameters.Count > 0)
        {
          // need selfinstantiation
          targetType = targetType.GetGenericTemplateInstance(this.assemblyBeingRewritten, wrapperType.ConsolidatedTemplateParameters);
        }
      }
      Method targetMethod = GetMatchingMethod(targetType, templateMethod, wrapperMethod);
      if (targetMethod.IsGeneric) {
        if (typeParameters.Count > targetMethod.TemplateParameters.Count) {
          // omit the extra constrained type arg.
          TypeNodeList origArgs = new TypeNodeList();
          for (int i = 0; i < targetMethod.TemplateParameters.Count; i++) {
            origArgs.Add(typeParameters[i]);
          }
          targetMethod = targetMethod.GetTemplateInstance(wrapperType, origArgs);
        }
        else {
          targetMethod = targetMethod.GetTemplateInstance(wrapperType, typeParameters);
        }
      }
      MethodCall call;
      NodeType callType = virtcall ? NodeType.Callvirt : NodeType.Call;
      if (isProtected) {
        var mb = new MemberBinding(wrapperMethod.ThisParameter, targetMethod);
        var elist = new ExpressionList(wrapperMethod.Parameters.Count);
        for (int i = 0; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(mb, elist, callType);
      }
      else if (templateMethod.IsStatic) {
        var elist = new ExpressionList(wrapperMethod.Parameters.Count);
        for (int i = 0; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(new MemberBinding(null, targetMethod), elist, callType);
      }
      else {
        var mb = new MemberBinding(wrapperMethod.Parameters[0], targetMethod);
        var elist = new ExpressionList(wrapperMethod.Parameters.Count - 1);
        for (int i = 1; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(mb, elist, callType);
      }
      if (constraintTypeParam != null) {
        call.Constraint = asTypeConstraintTypeParam;
      }
      if (HelperMethods.IsVoidType(templateMethod.ReturnType)) {
        sl.Add(new ExpressionStatement(call,callingContext));
        sl.Add(new Return(callingContext));
      }
      else {
        sl.Add(new Return(call,callingContext));
      }
      wrapperMethod.Body = b;

      wrapperType.Members.Add(wrapperMethod);
      return wrapperMethod;
    }
Example #3
0
    public override Expression VisitOldExpression(OldExpression oldExpression) {
      if (this.topLevelClosureClass != null) {
        #region In Closure ==> Create a field
        // Since we're within a closure, we can't create a local to hold the value of the old expression
        // but instead have to create a field for it. That field can be a member of the top-level
        // closure class since nothing mentioned in the old expression (except possibly for the
        // bound variables of enclosing quantifications) should be anything captured from
        // an inner anonymous delegate.

        // BUT, first we have to know if the old expression depends on any of the bound
        // variables of the closures in which it is located. If not, then we can implement
        // it as a scalar and just generate the assignment "closure_class.field := e" for
        // "Old(e)" to take a snapshot of e's value in the prestate. If it does depend on
        // any of the bound variables, then we need to generate a set of for-loops that
        // compute the indices and values of e for each tuple of indices so it can be retrieved
        // (given the indices) in the post-state.
        CollectBoundVariables cbv = new CollectBoundVariables(this.stackOfBoundVariables);
        cbv.VisitExpression(oldExpression.expression);

        SubstituteClosureClassWithinOldExpressions subst =
            new SubstituteClosureClassWithinOldExpressions(this.closureLocals);
        Expression e = subst.VisitExpression(oldExpression.expression);
        if (cbv.FoundVariables.Count == 0) {
          #region Use a scalar for the old variable
          Local closureLocal;
          if (!this.closureLocals.TryGetValue(this.topLevelClosureClass, out closureLocal))
          {
            Contract.Assume(false, "can't find closure local!");
          }
          #region Define a scalar
          var clTemplate = HelperMethods.Unspecialize(this.topLevelClosureClass);
          Field f = new Field(clTemplate,
            null,
            FieldFlags.CompilerControlled | FieldFlags.Public,
            Identifier.For("_old" + oldExpression.expression.UniqueKey.ToString()), // unique name for this old expr.
            oldExpression.Type,
            null);
          clTemplate.Members.Add(f);
          // now produce properly instantiated field
          f = (Field)Rewriter.GetMemberInstanceReference(f, this.topLevelClosureClass);
          #endregion
          #region Generate code to store value in prestate
          this.prestateValuesOfOldExpressions.Statements.Add(new AssignmentStatement(new MemberBinding(closureLocal, f), e));
          #endregion
          #region Return expression to be used in poststate
          // Return an expression that will evaluate in the poststate to the value of the old
          // expression in the prestate. This will be this.up.f where "up" is the field C#
          // generated to point to the instance of the top-level closure class.
          if (this.PointerToTopLevelClosureClass == null) {
            // then the old expression occurs in the top-level closure class. Just return "this.f"
            // where "this" refers to the top-level closure class.
            return new MemberBinding(new This(this.currentClosureClass), f);
          } else {
            return new MemberBinding(
              new MemberBinding(new This(this.currentClosureClass), this.PointerToTopLevelClosureClass),
              f);
          }
          #endregion
          #endregion
        } else {
          // the Old expression *does* depend upon at least one of the bound variable
          // in a ForAll or Exists expression
          #region Use an indexed variable for the old variable
          TypeNode oldVariableTypeDomain;
          #region Decide if domain is one-dimensional or not
          bool oneDimensional = cbv.FoundVariables.Count == 1 && cbv.FoundVariables[0].Type.IsValueType;
          if (oneDimensional) {
            // a one-dimensional old-expression can use the index variable directly
            oldVariableTypeDomain = cbv.FoundVariables[0].Type;
          } else {
            oldVariableTypeDomain = SystemTypes.GenericList.GetTemplateInstance(this.module, SystemTypes.Int32);
          }
          #endregion
          TypeNode oldVariableTypeRange = oldExpression.Type;
          TypeNode oldVariableType = SystemTypes.GenericDictionary.GetTemplateInstance(this.module, oldVariableTypeDomain, oldVariableTypeRange);
          Local closureLocal;
          if (!this.closureLocals.TryGetValue(this.topLevelClosureClass, out closureLocal))
          {
            Contract.Assume(false, "can't find closure local");
          }
          #region Define an indexed variable
          var clTemplate = HelperMethods.Unspecialize(this.topLevelClosureClass);
          Field f = new Field(clTemplate,
            null,
            FieldFlags.CompilerControlled | FieldFlags.Assembly, // can't be private or protected because it needs to be accessed from inner (closure) classes that don't inherit from the class this field is added to.
            Identifier.For("_old" + oldExpression.expression.UniqueKey.ToString()), // unique name for this old expr.
            oldVariableType,
            null);
          clTemplate.Members.Add(f);
          // instantiate f
          f = (Field)Rewriter.GetMemberInstanceReference(f, closureLocal.Type);
          #endregion
          #region Generate code to initialize the indexed variable
          Statement init = new AssignmentStatement(
            new MemberBinding(closureLocal, f),
            new Construct(new MemberBinding(null, oldVariableType.GetConstructor()), null));
          this.prestateValuesOfOldExpressions.Statements.Add(init);
          #endregion
          #region Generate code to store values in prestate
          #region Create assignment: this.closure.f[i,j,k,...] = e;
          Method setItem = oldVariableType.GetMethod(Identifier.For("set_Item"), oldVariableTypeDomain, oldVariableTypeRange);
          Expression index;
          if (oneDimensional) {
            index = cbv.FoundVariables[0];
          } else {
            //InstanceInitializer ctor =
            //  ContractNodes.TupleClass.GetConstructor(SystemTypes.Int32.GetArrayType(1));
            //Expression index = new Construct(new MemberBinding(null,ctor),new ExpressionList(
            index = Literal.Null;
          }
          MethodCall mc = new MethodCall(new MemberBinding(new MemberBinding(closureLocal, f), setItem),
            new ExpressionList(index, e));
          Statement stat = new ExpressionStatement(mc);
          #endregion
          List<Local> locals = new List<Local>(this.stackOfBoundVariables.Count);
          TrivialHashtable paramMap = new TrivialHashtable();
          #region Generate a local for each bound variable to use in for-loop
          foreach (Variable v in this.stackOfBoundVariables) {
            Local l = new Local(Identifier.Empty, v.Type);
            paramMap[v.UniqueKey] = l;
            locals.Add(l);
          }
          #endregion
          #region Substitute locals for bound variables in old expression *AND* in inner loop bounds
          SubstituteParameters sps = new SubstituteParameters(paramMap, this.stackOfBoundVariables);
          sps.Visit(stat);
          #endregion
          #region Create nested for-loops around assignment
          // keep track of when the first variable is used (from innermost to outermost)
          // as soon as the first one is needed because the old expression depends on it,
          // then keep all enclosing loops. It would be possible to keep only those where
          // the necessary loops have loop bounds that depend on an enclosing loop, but I
          // haven't calculated that, so just keep them all. For instance, if the old expression
          // depends on j and the loops are "for i,0,n" and inside that "for j,0,i", then need
          // both loops. If the inner loop bounds were 0 and n, then wouldn't need the outer
          // loop.
          bool usedAVariable = false;
          for (int i = this.stackOfBoundVariables.Count - 1; 0 <= i; i--) {
            if (!usedAVariable
              && !cbv.FoundVariables.Contains(this.stackOfBoundVariables[i])) continue;
            usedAVariable = true;
            Expression lowerBound = new Duplicator(this.module, this.currentClosureClass).VisitExpression(
              this.stackOfMethods[i].Operands[0]);
            lowerBound = subst.VisitExpression(lowerBound);
            lowerBound = sps.VisitExpression(lowerBound);
            Expression upperBound = new Duplicator(this.module, this.currentClosureClass).VisitExpression(
              this.stackOfMethods[i].Operands[1]);
            upperBound = subst.VisitExpression(upperBound);
            upperBound = sps.VisitExpression(upperBound);
            stat = RewriteHelper.GenerateForLoop(locals[i], lowerBound, upperBound, stat);
          }
          #endregion
          this.prestateValuesOfOldExpressions.Statements.Add(stat);
          #endregion
          #region Return expression to be used in poststate
          Method getItem = oldVariableType.GetMethod(Identifier.For("get_Item"), oldVariableTypeDomain);
          if (oneDimensional) {
            index = cbv.FoundReferences[0];
          } else {
            //InstanceInitializer ctor =
            //  ContractNodes.TupleClass.GetConstructor(SystemTypes.Int32.GetArrayType(1));
            //Expression index = new Construct(new MemberBinding(null,ctor),new ExpressionList(
            index = Literal.Null;
          }
          // Return an expression that will evaluate in the poststate to the value of the old
          // expression in the prestate. This will be this.up.f[i,j,k,...] where "up" is the field C#
          // generated to point to the instance of the top-level closure class.
          MemberBinding thisDotF;
          if (this.PointerToTopLevelClosureClass == null) {
            // then the old expression occurs in the top-level closure class. Just return "this.f"
            // where "this" refers to the top-level closure class.
            Contract.Assume(f != null);
            thisDotF = new MemberBinding(new This(clTemplate), HelperMethods.Unspecialize(f));
          } else {
            thisDotF = new MemberBinding(
              new MemberBinding(new This(clTemplate), this.PointerToTopLevelClosureClass),
              f);
          }
          return new MethodCall(new MemberBinding(thisDotF, getItem), new ExpressionList(index));
          #endregion
          #endregion
        }
        #endregion
      } else {
        #region Not in closure ==> Create a local variable
        Local l = GetLocalForOldExpression(oldExpression);
        #region Make sure local can be seen in the debugger (for the entire method, unfortunately)
        if (currentMethod.LocalList == null) {
          currentMethod.LocalList = new LocalList();
        }
        currentMethod.LocalList.Add(l);
        currentMethod.Body.HasLocals = true;
        #endregion
        this.prestateValuesOfOldExpressions.Statements.Add(
          new AssignmentStatement(l, oldExpression.expression));

        // Return an expression that will evaluate in the poststate to the value of the old
        // expression in the prestate. When we're not in a closure, this is just the local
        // itself.
        return l;
        #endregion
      }
    }
Example #4
0
    internal static Method GetMethodInstanceReference(Method methodOfGenericType, TypeNode instantiatedParentType)
    {
      //F:
      Contract.Requires(methodOfGenericType != null);
      Contract.Requires(instantiatedParentType != null);

      return (Method)GetMemberInstanceReference(methodOfGenericType, instantiatedParentType);
#if false
      int index = MemberIndexInTypeMembers(methodOfGenericType);

      // now try to find same index in instance wrapper type

      Method instMethod = null;
      var members = instantiatedParentType.Members;
      if (index < members.Count)
      {
        instMethod = members[index] as Method;
        Debug.Assert(instMethod == null || instMethod.Name.UniqueIdKey == methodOfGenericType.Name.UniqueIdKey);
      }
      if (instMethod == null)
      {
        // instantiation order did not work out, so we need to fake it.
        Duplicator dup = new Duplicator(this.assemblyBeingRewritten, instantiatedParentType);
        dup.RecordOriginalAsTemplate = true;
        instMethod = dup.VisitMethod(methodOfGenericType);
        var spec = TypeParameterSpecialization(methodOfGenericType.DeclaringType, instantiatedParentType);
        instMethod = spec.VisitMethod(instMethod);
        instMethod.DeclaringType = instantiatedParentType;
        AddMemberAtIndex(index, instantiatedParentType, instMethod);
      }
      return instMethod;
#endif
    }
Example #5
0
    internal static Member GetMemberInstanceReference(Member memberOfGenericType, TypeNode instantiatedParentType)
    {
      // F:
      Contract.Requires(memberOfGenericType != null);
      Contract.Requires(instantiatedParentType != null);

      if (instantiatedParentType.Template == null) { return memberOfGenericType; }

      int index = MemberIndexInTypeMembers(memberOfGenericType);

      // now try to find same index in instance wrapper type

      Member instMember = null;
      var members = instantiatedParentType.Members;
      if (index < members.Count)
      {
        instMember = members[index];
        //F: 
        Contract.Assume(memberOfGenericType.Name != null);
        Debug.Assert(instMember == null || instMember.Name.UniqueIdKey == memberOfGenericType.Name.UniqueIdKey);
      }
      if (instMember == null)
      {
        // F:
        Contract.Assume(memberOfGenericType.DeclaringType != null);

        // instantiation order did not work out, so we need to fake it.
        Duplicator dup = new Duplicator(memberOfGenericType.DeclaringType.DeclaringModule, instantiatedParentType);
        dup.RecordOriginalAsTemplate = true;
        instMember = (Member)dup.Visit(memberOfGenericType);
        var spec = TypeParameterSpecialization(memberOfGenericType.DeclaringType, instantiatedParentType);
        instMember = (Member)spec.Visit(instMember);
        instMember.DeclaringType = instantiatedParentType;
        AddMemberAtIndex(index, instantiatedParentType, instMember);
      }
      return instMember;
    }
Example #6
0
 Expression Duplicate(Expression e, TypeNode referringType) {
   Duplicator dup = new Duplicator(this.module, referringType);
   return dup.VisitExpression(e);
 }
Example #7
0
        // Create a secondary constructor that provides for initialization of
        // the "this" pointer as well as the input parameters
        private void ExtendMethodConstructor(Class newClass, ZMethod zMethod)
        {
            int numAddedParams = 0;

            // Duplicate our basic constructor so we can make an extended version
            System.Compiler.Duplicator dup = new System.Compiler.Duplicator(null, null);
            InstanceInitializer ctor = dup.VisitInstanceInitializer((InstanceInitializer)newClass.Members[0]);

            if (!zMethod.IsStatic)
            {
                // For instance methods, add a "This" parameter to the constructor
                ctor.Parameters.Add(new Parameter(Identifier.For("This"), new TypeExpression(Identifier.For("Pointer"))));

                // this.This = This;
                ctor.Body.Statements.Add(
                    new ExpressionStatement(
                        new AssignmentExpression(
                            new AssignmentStatement(
                                new QualifiedIdentifier(new This(), Identifier.For("This")),
                                Identifier.For("This"))))
                );

                numAddedParams++;
            }

            for (int i = 0, n = zMethod.Parameters.Count; i < n; i++)
            {
                TypeNode paramType;
                Parameter param = zMethod.Parameters[i];

                if (param == null || param.Type == null)
                    continue;

                if (param.IsOut)
                    continue;

                if (GetTypeClassification(param.Type) == TypeClassification.Heap)
                    paramType = this.ZingPtrType;
                else if (!IsPredefinedType(param.Type))
                    paramType = new TypeExpression(new QualifiedIdentifier(
                        new Identifier("Application"), param.Type.Name));
                else
                    paramType = param.Type;

                ctor.Parameters.Add(new Parameter(param.Name, paramType));
                // inputs.foo = foo;
                ctor.Body.Statements.Add(
                    new ExpressionStatement(
                        new AssignmentExpression(
                            new AssignmentStatement(
                                new QualifiedIdentifier(Identifier.For("inputs"), param.Name),
                                param.Name)))
                    );

                numAddedParams++;
            }

            // If we didn't actually add any parameters, then the basic constructor is
            // all that we need. Only add the new constructor if it's different.
            if (numAddedParams > 0)
            {
                newClass.Members.Add(ctor);
                ctor.DeclaringType = newClass;
            }
        }
Example #8
0
    /// <summary>
    /// If there is an anonymous delegate within a postcondition, then there
    /// will be a call to a delegate constructor.
    /// That call looks like "d..ctor(o,m)" where d is the type of the delegate.
    /// There are two cases depending on whether the anonymous delegate captured
    /// anything. In both cases, m is the method implementing the anonymous delegate.
    /// (1) It does capture something. Then o is the instance of the closure class
    /// implementing the delegate, and m is an instance method in the closure
    /// class.
    /// (2) It does *not* capture anything. Then o is the literal for null and
    /// m is a static method that was added directly to the class.
    /// 
    /// This method will cause the method (i.e., m) to be visited to collect any
    /// Result&lt;T&gt;() expressions that occur in it.
    /// </summary>
    /// <param name="cons">The AST representing the call to the constructor
    /// of the delegate type.</param>
    /// <returns>Whatever the base visitor returns</returns>
    public override Expression VisitConstruct(Construct cons) {
      if (cons.Type is DelegateNode) {
        UnaryExpression ue = cons.Operands[1] as UnaryExpression;
        if (ue == null) goto JustVisit;
        MemberBinding mb = ue.Operand as MemberBinding;
        if (mb == null) goto JustVisit;
        Method m = mb.BoundMember as Method;
        if (!HelperMethods.IsCompilerGenerated(m)) goto JustVisit;

        Contract.Assume(m != null);

        m = Definition(m);
        this.delegateNestingLevel++;
        TypeNode savedClosureClass = this.currentClosureClassInstance;
        Method savedClosureMethod = this.currentClosureMethod;
        Expression savedCurrentAccessToTopLevelClosure = this.currentAccessToTopLevelClosure;

        try
        {
          this.currentClosureMethod = m;

          if (m.IsStatic)
          {
            this.currentClosureClassInstance = null; // no closure object
          }
          else
          {
            this.currentClosureClassInstance = cons.Operands[0].Type;
            if (savedClosureClass == null)
            {
              // Then this is the top-level closure class.
              this.topLevelClosureClassInstance = this.currentClosureClassInstance;
              this.topLevelClosureClassDefinition = Definition(this.topLevelClosureClassInstance);
              this.currentAccessToTopLevelClosure = new This(this.topLevelClosureClassDefinition);
              this.properlyInstantiatedFieldType = this.originalLocalForResult.Type;

              if (this.topLevelMethodFormals != null) 
              {
                Contract.Assume(this.topLevelClosureClassDefinition.IsGeneric);
                Contract.Assume(topLevelClosureClassDefinition.TemplateParameters.Count >= this.topLevelMethodFormals.Count);

                // replace method type parameters in result properly with last n corresponding type parameters of closure class
                TypeNodeList closureFormals = topLevelClosureClassDefinition.TemplateParameters;
                if (closureFormals.Count > this.topLevelMethodFormals.Count)
                {
                  int offset = closureFormals.Count - this.topLevelMethodFormals.Count;
                  closureFormals = new TypeNodeList(this.topLevelMethodFormals.Count);
                  for (int i = 0; i < this.topLevelMethodFormals.Count; i++)
                  {
                    closureFormals.Add(topLevelClosureClassDefinition.TemplateParameters[i + offset]);
                  }
                }
                Duplicator dup = new Duplicator(this.declaringType.DeclaringModule, this.declaringType);
                Specializer spec = new Specializer(this.declaringType.DeclaringModule, topLevelMethodFormals, closureFormals);
                var type = dup.VisitTypeReference(this.originalLocalForResult.Type);
                type = spec.VisitTypeReference(type);
                this.properlyInstantiatedFieldType = type;
              }
            }
            else
            {
              while (currentClosureClassInstance.Template != null) currentClosureClassInstance = currentClosureClassInstance.Template;

              // Find the field in this.closureClass that the C# compiler generated
              // to point to the top-level closure
              foreach (Member mem in this.currentClosureClassInstance.Members)
              {
                Field f = mem as Field;
                if (f == null) continue;
                if (f.Type == this.topLevelClosureClassDefinition)
                {
                  var consolidatedTemplateParams = this.currentClosureClassInstance.ConsolidatedTemplateParameters;
                  TypeNode thisType;
                  if (consolidatedTemplateParams != null && consolidatedTemplateParams.Count > 0) {
                    thisType = this.currentClosureClassInstance.GetGenericTemplateInstance(this.assemblyBeingRewritten, consolidatedTemplateParams);
                  }
                  else {
                    thisType = this.currentClosureClassInstance;
                  }
                  this.currentAccessToTopLevelClosure = new MemberBinding(new This(thisType), f);

                  break;
                }
              }
            }
          }
          this.VisitBlock(m.Body);
        }
        finally
        {
          this.delegateNestingLevel--;
          this.currentClosureMethod = savedClosureMethod;
          this.currentClosureClassInstance = savedClosureClass;
          this.currentAccessToTopLevelClosure = savedCurrentAccessToTopLevelClosure;
        }
      }
    JustVisit:
      return base.VisitConstruct(cons);
    }
Example #9
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())));
        }
Example #10
0
    private Class MakeContractException() {
      Class contractExceptionType;

      #region If we're rewriting an assembly for v4 or above and it *isn't* Silverlight (so serialization support is needed), then use new embedded dll as the type
      if (4 <= TargetPlatform.MajorVersion) {
        var iSafeSerializationData = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Runtime.Serialization"), Identifier.For("ISafeSerializationData")) as Interface;
        if (iSafeSerializationData != null) {
          // Just much easier to write the C# and have the compiler generate everything than to try and create it all manually
          System.Reflection.Assembly embeddedAssembly;
          Stream embeddedAssemblyStream;
          embeddedAssembly = System.Reflection.Assembly.GetExecutingAssembly();
          embeddedAssemblyStream = embeddedAssembly.GetManifestResourceStream("Microsoft.Contracts.Foxtrot.InternalException.dll");
          byte[] data = new byte[0];
          using (var br = new BinaryReader(embeddedAssemblyStream)) {
            var len = embeddedAssemblyStream.Length;
            if (len < Int32.MaxValue)
              data = br.ReadBytes((int)len);
            AssemblyNode assemblyNode = AssemblyNode.GetAssembly(data, TargetPlatform.StaticAssemblyCache, true, false, true);
            contractExceptionType = assemblyNode.GetType(Identifier.For(""), Identifier.For("ContractException")) as Class;
          }
          if (contractExceptionType == null)
            throw new RewriteException("Tried to create the ContractException type from the embedded dll, but failed");
          var d = new Duplicator(this.targetAssembly, this.RuntimeContractType);
          d.FindTypesToBeDuplicated(new TypeNodeList(contractExceptionType));

          var ct = d.Visit(contractExceptionType);
          contractExceptionType = (Class)ct;
          contractExceptionType.Flags |= TypeFlags.NestedPrivate;
          this.RuntimeContractType.Members.Add(contractExceptionType);
          return contractExceptionType;
        }
      }
      #endregion

      contractExceptionType = new Class(this.targetAssembly, this.RuntimeContractType, new AttributeList(), TypeFlags.Class | TypeFlags.NestedPrivate | TypeFlags.Serializable, null, Identifier.For("ContractException"), SystemTypes.Exception, null, null);

      RewriteHelper.TryAddCompilerGeneratedAttribute(contractExceptionType);

      var kindField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_Kind"), contractNodes.ContractFailureKind, null);
      var userField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_UserMessage"), SystemTypes.String, null);
      var condField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_Condition"), SystemTypes.String, null);
      contractExceptionType.Members.Add(kindField);
      contractExceptionType.Members.Add(userField);
      contractExceptionType.Members.Add(condField);

      #region Constructor for setting the fields
      var parameters = new ParameterList();
      var kindParam = new Parameter(Identifier.For("kind"), this.contractNodes.ContractFailureKind);
      var failureParam = new Parameter(Identifier.For("failure"), SystemTypes.String);
      var usermsgParam = new Parameter(Identifier.For("usermsg"), SystemTypes.String);
      var conditionParam = new Parameter(Identifier.For("condition"), SystemTypes.String);
      var innerParam = new Parameter(Identifier.For("inner"), SystemTypes.Exception);
      parameters.Add(kindParam);
      parameters.Add(failureParam);
      parameters.Add(usermsgParam);
      parameters.Add(conditionParam);
      parameters.Add(innerParam);
      var body = new Block(new StatementList());
      var ctor = new InstanceInitializer(contractExceptionType, null, parameters, body);
      ctor.Flags |= MethodFlags.Public | MethodFlags.HideBySig;
      ctor.CallingConvention = CallingConventionFlags.HasThis;
      body.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(ctor.ThisParameter, contractExceptionType.BaseClass.GetConstructor(SystemTypes.String, SystemTypes.Exception)), new ExpressionList(failureParam, innerParam))));
      body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, kindField), kindParam));
      body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, userField), usermsgParam));
      body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, condField), conditionParam));
      body.Statements.Add(new Return());
      contractExceptionType.Members.Add(ctor);
      #endregion

      if (SystemTypes.SerializationInfo != null && SystemTypes.SerializationInfo.BaseClass != null) {
        // Silverlight (e.g.) is a platform that doesn't support serialization. So check to make sure the type really exists.
        // 
        var baseCtor = SystemTypes.Exception.GetConstructor(SystemTypes.SerializationInfo, SystemTypes.StreamingContext);

        if (baseCtor != null) {
          #region Deserialization Constructor
          parameters = new ParameterList();
          var info = new Parameter(Identifier.For("info"), SystemTypes.SerializationInfo);
          var context = new Parameter(Identifier.For("context"), SystemTypes.StreamingContext);
          parameters.Add(info);
          parameters.Add(context);
          body = new Block(new StatementList());
          ctor = new InstanceInitializer(contractExceptionType, null, parameters, body);
          ctor.Flags |= MethodFlags.Private | MethodFlags.HideBySig;
          ctor.CallingConvention = CallingConventionFlags.HasThis;
          // : base(info, context) 
          body.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(ctor.ThisParameter, baseCtor), new ExpressionList(info, context))));
          // _Kind = (ContractFailureKind)info.GetInt32("Kind");
          var getInt32 = SystemTypes.SerializationInfo.GetMethod(Identifier.For("GetInt32"), SystemTypes.String);
          body.Statements.Add(new AssignmentStatement(
              new MemberBinding(new This(), kindField),
              new MethodCall(new MemberBinding(info, getInt32), new ExpressionList(new Literal("Kind", SystemTypes.String)))
              ));
          // _UserMessage = info.GetString("UserMessage");
          var getString = SystemTypes.SerializationInfo.GetMethod(Identifier.For("GetString"), SystemTypes.String);
          body.Statements.Add(new AssignmentStatement(
              new MemberBinding(new This(), userField),
              new MethodCall(new MemberBinding(info, getString), new ExpressionList(new Literal("UserMessage", SystemTypes.String)))
              ));
          // _Condition = info.GetString("Condition");
          body.Statements.Add(new AssignmentStatement(
              new MemberBinding(new This(), condField),
              new MethodCall(new MemberBinding(info, getString), new ExpressionList(new Literal("Condition", SystemTypes.String)))
              ));
          body.Statements.Add(new Return());
          contractExceptionType.Members.Add(ctor);
          #endregion

          #region GetObjectData

          var securityCriticalCtor = SystemTypes.SecurityCriticalAttribute.GetConstructor();
          var securityCriticalAttribute = new AttributeNode(new MemberBinding(null, securityCriticalCtor), null, System.AttributeTargets.Method);
          var attrs = new AttributeList(securityCriticalAttribute);
          parameters = new ParameterList();
          info = new Parameter(Identifier.For("info"), SystemTypes.SerializationInfo);
          context = new Parameter(Identifier.For("context"), SystemTypes.StreamingContext);
          parameters.Add(info);
          parameters.Add(context);
          body = new Block(new StatementList());
          var getObjectDataName = Identifier.For("GetObjectData");
          var getObjectData = new Method(contractExceptionType, attrs, getObjectDataName, parameters, SystemTypes.Void, body);
          getObjectData.CallingConvention = CallingConventionFlags.HasThis;
          // public override
          getObjectData.Flags = MethodFlags.Public | MethodFlags.Virtual;
          // base.GetObjectData(info, context);
          var baseGetObjectData = SystemTypes.Exception.GetMethod(getObjectDataName, SystemTypes.SerializationInfo, SystemTypes.StreamingContext);
          body.Statements.Add(new ExpressionStatement(
            new MethodCall(new MemberBinding(new This(), baseGetObjectData), new ExpressionList(info, context), NodeType.Call, SystemTypes.Void)
            ));
          // info.AddValue("Kind", _Kind);
          var addValueObject = SystemTypes.SerializationInfo.GetMethod(Identifier.For("AddValue"), SystemTypes.String, SystemTypes.Object);
          body.Statements.Add(new ExpressionStatement(
            new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("Kind", SystemTypes.String), new BinaryExpression(new MemberBinding(new This(), kindField), new Literal(contractNodes.ContractFailureKind), NodeType.Box)), NodeType.Call, SystemTypes.Void)
            ));
          // info.AddValue("UserMessage", _UserMessage);
          body.Statements.Add(new ExpressionStatement(
            new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("UserMessage", SystemTypes.String), new MemberBinding(new This(), userField)), NodeType.Call, SystemTypes.Void)
            ));
          // info.AddValue("Condition", _Condition);
          body.Statements.Add(new ExpressionStatement(
            new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("Condition", SystemTypes.String), new MemberBinding(new This(), condField)), NodeType.Call, SystemTypes.Void)
            ));

          body.Statements.Add(new Return());
          contractExceptionType.Members.Add(getObjectData);
          #endregion
        }
      }

      this.RuntimeContractType.Members.Add(contractExceptionType);
      return contractExceptionType;
    }
Example #11
0
    public override void VisitTypeNode(TypeNode typeNode) {
      if (typeNode == null) return;

      if (HelperMethods.IsContractTypeForSomeOtherType(typeNode, this.rewriterNodes) != null) {
        return;
      }
      Method savedInvariantMethod = this.InvariantMethod;
      Field savedReentrancyFlag = this.ReentrancyFlag;
      this.InvariantMethod = null;
      this.ReentrancyFlag = null;
      var savedState = this.currentState;
      this.currentState = new CurrentState(typeNode);
      var savedEmitFlags = this.AdaptRuntimeOptionsBasedOnAttributes(typeNode.Attributes);

      try
      {
        if (this.Emit(RuntimeContractEmitFlags.Invariants) && rewriterNodes.InvariantMethod != null)
        {
          InvariantList userWrittenInvariants = typeNode.Contract == null ? null : typeNode.Contract.Invariants;
          Class asClass = typeNode as Class;
          Field baseReentrancyFlag;
          Method baseInvariantMethod = FindAndInstantiateBaseClassInvariantMethod(asClass, out baseReentrancyFlag);


          if ((userWrittenInvariants != null && 0 < userWrittenInvariants.Count) || baseInvariantMethod != null)
          {
            Field reEntrancyFlag = null;
            var isStructWithExplicitLayout = IsStructWithExplicitLayout(typeNode as Struct);
            if (isStructWithExplicitLayout)
            {
              this.HandleError(new Warning(1044, String.Format("Struct '{0}' has explicit layout and an invariant. Invariant recursion guards will not be emitted and evaluation of invariants may occur too eagerly.", typeNode.FullName), new SourceContext()));
            }
            else
            {
              #region Find or create re-entrancy flag to the class
              if (baseReentrancyFlag != null)
              {
                // grab base reEntrancyFlag
                reEntrancyFlag = baseReentrancyFlag;
              }
              else
              {
                FieldFlags reentrancyFlagProtection;
                if (typeNode.IsSealed)
                {
                  reentrancyFlagProtection = FieldFlags.Private | FieldFlags.CompilerControlled;
                }
                else if (this.InheritInvariantsAcrossAssemblies)
                {
                  reentrancyFlagProtection = FieldFlags.Family | FieldFlags.CompilerControlled;
                }
                else
                {
                  reentrancyFlagProtection = FieldFlags.FamANDAssem | FieldFlags.CompilerControlled;
                }
                reEntrancyFlag = new Field(typeNode, null, reentrancyFlagProtection, Identifier.For("$evaluatingInvariant$"), SystemTypes.Boolean, null);
                RewriteHelper.TryAddCompilerGeneratedAttribute(reEntrancyFlag);
                RewriteHelper.TryAddDebuggerBrowsableNeverAttribute(reEntrancyFlag);
                typeNode.Members.Add(reEntrancyFlag);
              }
              #endregion Add re-entrancy flag to the class
            }
            Block newBody = new Block(new StatementList(3));
            // newBody ::=
            //   if (this.$evaluatingInvariant$){
            //     return (true); // don't really return true since this is a void method, but it means the invariant is assumed to hold
            //   this.$evaluatingInvariant$ := true;
            //   try{
            //     <evaluate invariants and call base invariant method>
            //   } finally {
            //     this.$evaluatingInvariant$ := false;
            //   }
            Method invariantMethod =
              new Method(
                typeNode,
                new AttributeList(),
                Identifier.For("$InvariantMethod$"),
                null,
                SystemTypes.Void,
                newBody);
            RewriteHelper.TryAddCompilerGeneratedAttribute(invariantMethod);
            invariantMethod.CallingConvention = CallingConventionFlags.HasThis;
            if (this.InheritInvariantsAcrossAssemblies)
              invariantMethod.Flags = MethodFlags.Family | MethodFlags.Virtual;
            else
              invariantMethod.Flags = MethodFlags.FamANDAssem | MethodFlags.Virtual;
            invariantMethod.Attributes.Add(new AttributeNode(new MemberBinding(null, this.runtimeContracts.ContractNodes.InvariantMethodAttribute.GetConstructor()), null));

            #region call base class invariant
            if (baseInvariantMethod != null)
            {
              newBody.Statements.Add(
                new ExpressionStatement(
                new MethodCall(
                new MemberBinding(invariantMethod.ThisParameter, baseInvariantMethod), null, NodeType.Call, SystemTypes.Void)));
            }
            #endregion
            #region Add re-entrancy test to the method
            Block invariantExit = new Block();
            if (reEntrancyFlag != null)
            {
              Block reEntrancyTest = new Block(new StatementList());
              reEntrancyTest.Statements.Add(
                new Branch(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), invariantExit));
              reEntrancyTest.Statements.Add(
                new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.True)
                );
              newBody.Statements.Add(reEntrancyTest);
            }
            #endregion Add re-entrancy test to the method

            Block invariantChecks = new Block(new StatementList());
            if (userWrittenInvariants != null)
            {
              #region Filter out invariants that aren't runtime checkable
              var filteredInvariants = new InvariantList();
              foreach (var i in userWrittenInvariants) {
                if (!EmitInvariant(i, this.skipQuantifiers)) continue;
                filteredInvariants.Add(i);
              }
              #endregion Filter out invariants that aren't runtime checkable
              #region Duplicate the invariants
              // need to duplicate the invariants so they aren't shared
              Duplicator d = new Duplicator(typeNode.DeclaringModule, typeNode);
              InvariantList duplicatedInvariants = d.VisitInvariantList(filteredInvariants);
              // F: seems to have the invariant duplictedInvariants != null
              Contract.Assume(duplicatedInvariants != null);

              #endregion Duplicate the invariants
              #region Rewrite the body of the invariant method
              // then we need to replace calls to Contract.Invariant with calls to Contract.RewriterInvariant
              // in the body of the invariant method
              RewriteInvariant rc = new RewriteInvariant(this.runtimeContracts);
              rc.VisitInvariantList(duplicatedInvariants);
              #endregion Rewrite the body of the invariant method
              for (int i = 0, n = duplicatedInvariants.Count; i < n; i++)
              {
                Expression e = duplicatedInvariants[i].Condition;
                var blockExpr = e as BlockExpression;
                if (blockExpr != null)
                {
                  invariantChecks.Statements.Add(blockExpr.Block);
                }
                else
                {
                  invariantChecks.Statements.Add(new ExpressionStatement(e));
                }
              }
            }
            Block finallyB = new Block(new StatementList(1));
            if (reEntrancyFlag != null)
            {
              finallyB.Statements.Add(
                new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.False)
                );
            }
            this.cleanUpCodeCoverage.VisitBlock(invariantChecks);
            Block b = RewriteHelper.CreateTryFinallyBlock(invariantMethod, invariantChecks, finallyB);
            newBody.Statements.Add(b);
            newBody.Statements.Add(invariantExit);
            newBody.Statements.Add(new Return());

            // set the field "this.InvariantMethod" to this one so it is used in calls within each method
            // but don't add it yet to the class so it doesn't get visited!
            this.InvariantMethod = invariantMethod;
            this.ReentrancyFlag = reEntrancyFlag;
          }
        }

        base.VisitTypeNode(typeNode);
        // Now add invariant method to the class
        if (this.InvariantMethod != null)
        {
          typeNode.Members.Add(this.InvariantMethod);
        }
        return;
      }
      finally
      {
        this.InvariantMethod = savedInvariantMethod;
        this.ReentrancyFlag = savedReentrancyFlag;
        this.currentState = savedState;
        this.contractEmitFlags = savedEmitFlags;
      }
    }
Example #12
0
        public virtual TypeNode/*!*/ GetTemplateInstance(Module module, TypeNode referringType, TypeNode declaringType, TypeNodeList templateArguments)
        {
            TypeNodeList templateParameters = this.TemplateParameters;
            if(module == null || templateArguments == null || (declaringType == null && (templateParameters == null || templateParameters.Count == 0)))
                return this;
            if(this.IsGeneric)
            {
                referringType = null;
                module = TypeNode.cachingModuleForGenericInstances;
            }
            bool notFullySpecialized;
            Identifier/*!*/ uniqueMangledName;
            Identifier mangledName = this.GetMangledTemplateInstanceName(templateArguments, out uniqueMangledName, out notFullySpecialized);
            TypeNode result;
            Identifier dummyId;
            this.TryToFindExistingInstance(module, declaringType, templateArguments, mangledName, uniqueMangledName, out result, out dummyId);
            if(result != null)
                return result;
            if(this.NewTemplateInstanceIsRecursive)
                return this; //An instance of this template is trying to instantiate the template again
            lock(Module.GlobalLock)
            {
                Identifier unusedMangledName;
                this.TryToFindExistingInstance(module, declaringType, templateArguments, mangledName, uniqueMangledName, out result, out unusedMangledName);
                if(result != null)
                    return result;
                //^ assume unusedMangledName != null;
                TypeNodeList consolidatedTemplateArguments =
                  declaringType == null ? templateArguments : declaringType.GetConsolidatedTemplateArguments(templateArguments);
                Duplicator duplicator = new Duplicator(module, referringType);
                duplicator.RecordOriginalAsTemplate = true;
                duplicator.SkipBodies = true;
                duplicator.TypesToBeDuplicated[this.UniqueKey] = this;
                result = duplicator.VisitTypeNode(this, unusedMangledName, consolidatedTemplateArguments, this.Template == null ? this : this.Template, true);
                //^ assume result != null;
                if(module == this.DeclaringModule)
                {
                    if(this.TemplateInstances == null)
                        this.TemplateInstances = new TypeNodeList();
                    this.TemplateInstances.Add(result);
                }
                result.Name = unusedMangledName;
                result.Name.SourceContext = this.Name.SourceContext;
                result.fullName = null;
                if(this.IsGeneric)
                    result.DeclaringModule = this.DeclaringModule;
                result.DeclaringType = this.IsGeneric || referringType == null ? declaringType : referringType;
                result.Template = this;
                result.templateParameters = new TypeNodeList();
                result.consolidatedTemplateParameters = new TypeNodeList();
                result.templateArguments = templateArguments;
                result.consolidatedTemplateArguments = consolidatedTemplateArguments;
                result.IsNotFullySpecialized = notFullySpecialized || (declaringType != null && declaringType.IsNotFullySpecialized);
                module.StructurallyEquivalentType[unusedMangledName.UniqueIdKey] = result;
                module.StructurallyEquivalentType[uniqueMangledName.UniqueIdKey] = result;
                Specializer specializer = new Specializer(module, this.ConsolidatedTemplateParameters, consolidatedTemplateArguments);
                specializer.VisitTypeNode(result);
                TypeFlags visibility = this.Flags & TypeFlags.VisibilityMask;
                for(int i = 0, m = templateArguments.Count; i < m; i++)
                {
                    TypeNode t = templateArguments[i];
                    if(t == null)
                        continue;
                    if(t is TypeParameter || t is ClassParameter || t.IsNotFullySpecialized)
                        continue;
                    visibility = TypeNode.GetVisibilityIntersection(visibility, t.Flags & TypeFlags.VisibilityMask);
                }
                result.Flags &= ~TypeFlags.VisibilityMask;
                result.Flags |= visibility;
                if(this.IsGeneric)
                    return result;

                return result;
            }
        }
Example #13
0
        public virtual Method/*!*/ GetTemplateInstance(TypeNode referringType, TypeNodeList typeArguments)
        {
            if(referringType == null || this.DeclaringType == null) { Debug.Assert(false); return this; }
            if(this.IsGeneric)
                referringType = this.DeclaringType;
            if(referringType != this.DeclaringType && referringType.DeclaringModule == this.DeclaringType.DeclaringModule)
                return this.GetTemplateInstance(this.DeclaringType, typeArguments);
            if(referringType.structurallyEquivalentMethod == null)
                referringType.structurallyEquivalentMethod = new TrivialHashtableUsingWeakReferences();
            Module module = referringType.DeclaringModule;
            if(module == null)
                return this;
            int n = typeArguments == null ? 0 : typeArguments.Count;
            if(n == 0 || typeArguments == null)
                return this;
            StringBuilder sb = new StringBuilder(this.Name.ToString());
            sb.Append('<');
            for(int i = 0; i < n; i++)
            {
                TypeNode ta = typeArguments[i];
                if(ta == null)
                    continue;
                sb.Append(ta.FullName);
                if(i < n - 1)
                    sb.Append(',');
            }
            sb.Append('>');
            Identifier mangledName = Identifier.For(sb.ToString());
            lock(this)
            {
                Method m = (Method)referringType.structurallyEquivalentMethod[mangledName.UniqueIdKey];
                int counter = 1;
                while(m != null)
                {
                    if(m.template == this && Method.TypeListsAreEquivalent(m.TemplateArguments, typeArguments))
                        return m;
                    mangledName = Identifier.For(mangledName.ToString() + counter++);
                    m = (Method)referringType.structurallyEquivalentMethod[mangledName.UniqueIdKey];
                }
                Duplicator duplicator = new Duplicator(referringType.DeclaringModule, referringType);
                duplicator.RecordOriginalAsTemplate = true;
                duplicator.SkipBodies = true;
                Method result = duplicator.VisitMethod(this);
                //^ assume result != null;
                result.Attributes = this.Attributes; //These do not get specialized, but may need to get normalized
                result.Name = mangledName;
                result.fullName = null;
                result.template = this;
                result.TemplateArguments = typeArguments;
                TypeNodeList templateParameters = result.TemplateParameters;
                result.TemplateParameters = null;

                result.IsNormalized = true;

                if(!this.IsGeneric)
                {
                    ParameterList pars = this.Parameters;
                    ParameterList rpars = result.Parameters;
                    if(pars != null && rpars != null && rpars.Count >= pars.Count)
                        for(int i = 0, count = pars.Count; i < count; i++)
                        {
                            Parameter p = pars[i];
                            Parameter rp = rpars[i];
                            if(p == null || rp == null)
                                continue;
                            rp.Attributes = p.Attributes; //These do not get specialized, but may need to get normalized
                        }
                }

                if(!this.IsGeneric && !(result.IsStatic) && this.DeclaringType != referringType)
                {
                    result.Flags &= ~(MethodFlags.Virtual | MethodFlags.NewSlot);
                    result.Flags |= MethodFlags.Static;
                    result.CallingConvention &= ~CallingConventionFlags.HasThis;
                    result.CallingConvention |= CallingConventionFlags.ExplicitThis;

                    ParameterList pars = result.Parameters;

                    if(pars == null)
                        result.Parameters = pars = new ParameterList();

                    Parameter thisPar = new Parameter(StandardIds.This, this.DeclaringType);
                    pars.Add(thisPar);

                    for(int i = pars.Count - 1; i > 0; i--)
                        pars[i] = pars[i - 1];

                    pars[0] = thisPar;
                }

                referringType.structurallyEquivalentMethod[mangledName.UniqueIdKey] = result;
                Specializer specializer = new Specializer(module, templateParameters, typeArguments);
                specializer.VisitMethod(result);
                if(this.IsGeneric) { result.DeclaringType = this.DeclaringType; return result; }
                if(this.IsAbstract)
                    return result;
                referringType.Members.Add(result);
                return result;
            }
        }
Example #14
0
        private static TypeNodeList CreateTemplateParameters(Class closureClass, TypeNodeList inputTemplateParameters, TypeNode declaringType)
        {
            Contract.Requires(closureClass != null);
            Contract.Requires(inputTemplateParameters != null);
            Contract.Requires(declaringType != null);

            var dup = new Duplicator(declaringType.DeclaringModule, declaringType);

            var templateParameters = new TypeNodeList();

            var parentCount = declaringType.ConsolidatedTemplateParameters.CountOrDefault();

            for (int i = 0; i < inputTemplateParameters.Count; i++)
            {
                var tp = HelperMethods.NewEqualTypeParameter(
                    dup, (ITypeParameter)inputTemplateParameters[i],
                    closureClass, parentCount + i);

                templateParameters.Add(tp);
            }

            return templateParameters;
        }
Example #15
0
        private static TypeNodeList DuplicateTypeParameterList(TypeNodeList typeParameters, int offsetIndex, TypeNode declaringType)
        {
            if (typeParameters == null) return null;

            Duplicator dup = new Duplicator(declaringType.DeclaringModule, null);
            dup.FindTypesToBeDuplicated(typeParameters);
            
            TypeNodeList result = dup.VisitTypeParameterList(typeParameters);
            
            for (int i = 0; i < result.Count; i++)
            {
                TypeNode tn = result[i];
                
                tn.DeclaringType = declaringType;
                tn.DeclaringModule = declaringType.DeclaringModule;

                ITypeParameter tp = (ITypeParameter) tn;
                
                tp.ParameterListIndex = offsetIndex + i;
                tp.DeclaringMember = declaringType;
            }

            return result;
        }
Example #16
0
 private Class CreateWrapperClass(Class c)
 {
   var flags = WrapperTypeFlags(c);
   var wrapper = new Class(this.assemblyBeingRewritten, null, null, flags, null, c.Name, SystemTypes.Object, null, null);
   RewriteHelper.TryAddCompilerGeneratedAttribute(wrapper);
   if (c.TemplateParameters != null)
   {
     Duplicator d = new Duplicator(this.assemblyBeingRewritten, wrapper);
     d.FindTypesToBeDuplicated(c.TemplateParameters);
     var templateParams = CopyTypeParameterList(wrapper, c, d);
     wrapper.TemplateParameters = templateParams;
     wrapper.IsGeneric = true;
   }
   return wrapper;
 }
Example #17
0
        public static TypeNode NewEqualTypeParameter(Duplicator dup, ITypeParameter itp, TypeNode declaringType, int index)
        {
            ClassParameter cp = itp as ClassParameter;
            if (cp != null)
            {
                ClassParameter mcp = new ClassParameter();
                
                mcp.Interfaces = dup.VisitInterfaceReferenceList(cp.Interfaces);
                mcp.BaseClass = cp.BaseClass;
                
                mcp.TypeParameterFlags = cp.TypeParameterFlags & ~TypeParameterFlags.VarianceMask;
                mcp.DeclaringType = declaringType;
                mcp.DeclaringModule = declaringType.DeclaringModule;
                
                mcp.Name = cp.Name;
                mcp.ParameterListIndex = index;
                mcp.DeclaringMember = declaringType;

                return mcp;
            }

            TypeParameter tp = itp as TypeParameter;
            if (tp != null)
            {
                TypeParameter mp = new TypeParameter();

                mp.Interfaces = dup.VisitInterfaceReferenceList(tp.Interfaces);
                mp.TypeParameterFlags = tp.TypeParameterFlags & ~TypeParameterFlags.VarianceMask;
                
                mp.DeclaringType = declaringType;
                mp.DeclaringModule = declaringType.DeclaringModule;
                
                mp.Name = tp.Name;
                mp.ParameterListIndex = index;
                mp.DeclaringMember = declaringType;

                return mp;
            }

            throw new NotImplementedException("unexpected type parameter kind");
        }
Example #18
0
    private static TypeNodeList CopyTypeParameterList(TypeNode target, TypeNode source, Duplicator d)
    {
      var result = d.VisitTypeParameterList(source.TemplateParameters);
      foreach (var tp in result)
      {

        var itp = (ITypeParameter)tp;

        itp.DeclaringMember = target;
        itp.TypeParameterFlags = itp.TypeParameterFlags & ~TypeParameterFlags.VarianceMask;
      }
      return result;
    }
        private static void AddInterfaceImplementationWrapper(Class Class, Method intfMethod, Method baseMethod)
        {
            var d = new Duplicator(Class.DeclaringModule, Class);
            
            d.SkipBodies = true;

            var copy = d.VisitMethod(baseMethod);
            
            copy.Flags = MethodFlags.Private | MethodFlags.HideBySig | MethodFlags.Virtual | MethodFlags.NewSlot |
                         MethodFlags.Final;
            
            copy.ImplementedInterfaceMethods = new MethodList(intfMethod);
            copy.Name = Identifier.For("InheritedInterfaceImplementationContractWrapper$" + intfMethod.Name.Name);
            copy.ClearBody();
            copy.ThisParameter.Type = Class;
            
            var bodyBlock = new Block(new StatementList());
            copy.Body = new Block(new StatementList(bodyBlock));

            // add call to baseMethod
            var calledMethod = (baseMethod.TemplateParameters != null && baseMethod.TemplateParameters.Count > 0)
                ? baseMethod.GetTemplateInstance(Class, copy.TemplateParameters)
                : baseMethod;

            var argList = new ExpressionList();
            for (int i = 0; i < copy.Parameters.Count; i++)
            {
                argList.Add(copy.Parameters[i]);
            }

            var callExpression = new MethodCall(new MemberBinding(copy.ThisParameter, calledMethod), argList);
            if (HelperMethods.IsVoidType(intfMethod.ReturnType))
            {
                bodyBlock.Statements.Add(new ExpressionStatement(callExpression));
            }
            else
            {
                bodyBlock.Statements.Add(new Return(callExpression));
            }
            
            Class.Members.Add(copy);
        }
Example #20
0
        private static TypeNodeList CreateTemplateParameters(Class closureClass, Method @from, TypeNode declaringType)
        {
            var dup = new Duplicator(declaringType.DeclaringModule, declaringType);

            var templateParameters = new TypeNodeList();

            var parentCount = declaringType.ConsolidatedTemplateParameters.CountOrDefault();

            for (int i = 0; i < from.TemplateParameters.Count; i++)
            {
                var tp = HelperMethods.NewEqualTypeParameter(
                    dup, (ITypeParameter)from.TemplateParameters[i],
                    closureClass, parentCount + i);

                templateParameters.Add(tp);
            }

            return templateParameters;
        }