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); //} } } }
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; }
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 } }
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 }
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; }
Expression Duplicate(Expression e, TypeNode referringType) { Duplicator dup = new Duplicator(this.module, referringType); return dup.VisitExpression(e); }
// 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; } }
/// <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<T>() 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); }
/// <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()))); }
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; }
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; } }
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; } }
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; } }
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; }
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; }
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; }
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"); }
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); }
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; }