private void AddAlternativeInvocation(BlockStatement block, IMethodDefinition fakeMethod, IMethodReference originalCall) { var context = new ReplacementMethodConstructionContext(host, originalCall, fakeMethod, block, log, null); var methodBuilder = context.GetMethodBuilder(); methodBuilder.BuildMethod(); }
public override void BuildMethod() { AddStatement.DeclareInterceptedType(field.ContainingType.ResolvedType); Context.Log.WriteTrace(" Adding: var interceptedField = interceptedType.GetField('{0}');", field.Name.Value); Context.Block.Statements.Add( Declare.Variable<FieldInfo>("interceptedField").As( Call.VirtualMethod("GetField", typeof (string)).ThatReturns<FieldInfo>().WithArguments( Constant.Of(field.Name.Value)).On("interceptedType")) ); AddStatement.DeclareArgumentsList(); var funcT = SharpMockTypes.Functions[0]; var funcActualT = new GenericTypeInstanceReference(); funcActualT.GenericType = funcT; funcActualT.GenericArguments.Add(field.Type); var accessor = new AnonymousDelegate(); accessor.Type = funcActualT; accessor.ReturnType = field.Type; accessor.CallingConvention = CallingConvention.HasThis; var accessorBody = new BlockStatement(); var returnActualField = new ReturnStatement(); var actualField = new BoundExpression(); actualField.Type = field.Type; actualField.Definition = field; returnActualField.Expression = actualField; accessorBody.Statements.Add(returnActualField); accessor.Body = accessorBody; Context.Block.Statements.Add( Declare.Variable("local_0", funcActualT).As(accessor) ); AddStatement.DeclareRegistryInterceptor(); AddStatement.DeclareInvocation(); AddStatement.SetArgumentsOnInvocation(); AddStatement.SetOriginalCallOnInvocation(); AddStatement.SetTargetOnInvocationToNull(); Context.Block.Statements.Add( Do(Call.PropertySetter<MemberInfo>("OriginalCallInfo").WithArguments("interceptedField").On("invocation")) ); AddStatement.CallShouldInterceptOnInterceptor(); AddStatement.CallInterceptOnInterceptor(); Context.Block.Statements.Add( Declare.Variable("interceptionResult", field.Type).As( ChangeType.Convert(Call.PropertyGetter<object>("Return").On("invocation")).To(field.Type)) ); Context.Block.Statements.Add(Return.Variable(Locals["interceptionResult"])); }
public ReplacementMethodConstructionContext(IMetadataHost host, IMethodReference originalCall, IMethodDefinition fakeMethod, BlockStatement block, ILogger log, IReplaceableReference originalReference) { this.host = host; this.block = block; this.log = log; this.originalReference = originalReference; this.originalCall = originalCall; fakeMethodParameters = fakeMethod.Parameters; returnType = fakeMethod.Type; }
public ConditionalStatement Else(VoidAction<List<IStatement>> code) { var blockStatements = new List<IStatement>(); code(blockStatements); var elseBranch = new BlockStatement(); elseBranch.Statements = blockStatements; ifStatement.FalseBranch = elseBranch; return ifStatement; }
public ReplacementMethodConstructionContext(IMetadataHost host, IFieldReference originalField, IMethodDefinition fakeMethod, BlockStatement block, bool isAssignment, ILogger log, IReplaceableReference originalReference) { this.host = host; this.block = block; this.originalField = originalField; this.isAssignment = isAssignment; this.log = log; this.originalReference = originalReference; fakeMethodParameters = fakeMethod.Parameters; returnType = fakeMethod.Type; }
static IStatement FindLastStatement(BlockStatement block) { IStatement result = null; while (block != null) { var i = block.Statements.Count-1; if (i < 0) return result; var nextBlock = block.Statements[i] as BlockStatement; if (nextBlock == null) return block.Statements[i]; if (i > 0) result = block.Statements[i-1]; block = nextBlock; } return null; }
static bool RemoveLastStatement(BlockStatement block, IStatement statement) { while (block != null) { var i = block.Statements.Count-1; if (i < 0) return false; if (block.Statements[i] == statement) { block.Statements.RemoveAt(i); return true; } block = block.Statements[i] as BlockStatement; } return false; }
internal PatternReplacer(SourceMethodBody sourceMethodBody, BlockStatement block) { Contract.Requires(sourceMethodBody != null); Contract.Requires(block != null); this.host = sourceMethodBody.host; Contract.Assume(this.host != null); this.nameTable = this.host.NameTable; this.gotosThatTarget = sourceMethodBody.gotosThatTarget; Contract.Assume(this.gotosThatTarget != null); this.numberOfAssignmentsToLocal = sourceMethodBody.numberOfAssignmentsToLocal; Contract.Assume(this.numberOfAssignmentsToLocal != null); this.numberOfReferencesToLocal = sourceMethodBody.numberOfReferencesToLocal; Contract.Assume(this.numberOfReferencesToLocal != null); this.bindingsThatMakeALastUseOfALocalVersion = sourceMethodBody.bindingsThatMakeALastUseOfALocalVersion; Contract.Assume(this.bindingsThatMakeALastUseOfALocalVersion != null); this.singleAssignmentReferenceFinder = new SingleAssignmentSingleReferenceFinder(this.bindingsThatMakeALastUseOfALocalVersion, this.numberOfReferencesToLocal); this.singleAssignmentLocalReplacer = new SingleAssignmentLocalReplacer(this.host, this.bindingsThatMakeALastUseOfALocalVersion, this.numberOfAssignmentsToLocal); this.sourceLocationProvider = sourceMethodBody.sourceLocationProvider; this.singleUseExpressionChecker = new SingleUseExpressionChecker(); Contract.Assume(sourceMethodBody.ilMethodBody != null); this.isVoidMethod = sourceMethodBody.ilMethodBody.MethodDefinition.Type.TypeCode == PrimitiveTypeCode.Void; while (block != null) { var n = block.Statements.Count; if (n > 0) { var nestedBlock = block.Statements[n-1] as BlockStatement; if (nestedBlock != null) { block = nestedBlock; continue; } } if (n >= 2) { // && sourceMethodBody.ilMethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void) { var labeledStatement = block.Statements[n-2] as LabeledStatement; if (labeledStatement == null && n >= 3 && block.Statements[n-2] is EmptyStatement) { labeledStatement = block.Statements[n-3] as LabeledStatement; } var returnStatement = block.Statements[n-1] as ReturnStatement; if (labeledStatement != null && returnStatement != null) { if (sourceMethodBody.ilMethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void) { var boundExpression = returnStatement.Expression as BoundExpression; if (boundExpression != null) { this.returnValueTemp = boundExpression.Definition as ILocalDefinition; if (this.returnValueTemp != null) { bool isCompilerGenerated = false; if (this.sourceLocationProvider != null) this.sourceLocationProvider.GetSourceNameFor(this.returnValueTemp, out isCompilerGenerated); if (isCompilerGenerated) { this.labelOfFinalReturn = labeledStatement.Label; this.finalBlock = block; } else { this.returnValueTemp = null; } } } } else { this.labelOfFinalReturn = labeledStatement.Label; } } } block = null; //TODO: putting a return here causes Clousot to conclude that the object invariant is never reached. } }
public override IMethodBody Rewrite(IMethodBody body) { var method = body.MethodDefinition; _log.Info("Rewriting IMethodBody of: " + method + " Pass: " + MutationTarget.PassInfo); var newBody = new SourceMethodBody(Host) { MethodDefinition = method, LocalsAreZeroed = true }; var block = new BlockStatement(); newBody.Block = block; var replacement = method.ContainingTypeDefinition.Methods.Single(m => m.ToString() == MutationTarget.PassInfo); var methodCall = new MethodCall { MethodToCall = replacement, Type = replacement.Type, ThisArgument = new ThisReference() {Type = method.ContainingTypeDefinition} }; foreach (var param in replacement.Parameters) { methodCall.Arguments.Add(new BoundExpression() { Definition = method.Parameters .First(p => ((INamedTypeReference)p.Type).Name.Value == ((INamedTypeReference)param.Type).Name.Value) }); // methodCall.Arguments.Add(method.Parameters.First(p => new )); } if (replacement.Type == Host.PlatformType.SystemVoid) { block.Statements.Add(new ExpressionStatement { Expression = methodCall }); block.Statements.Add(new ReturnStatement()); } else { block.Statements.Add(new ReturnStatement { Expression = methodCall }); } return newBody; }
public IExpression WithBody(VoidAction<ICodeBuilder> code) { method.Type = delegateType; method.CallingConvention = CallingConvention.HasThis; method.ReturnType = returnTypeReference; var codeBuilder = new CodeBuilder(host, method.Parameters); code(codeBuilder); var body = new BlockStatement(); foreach (var statement in codeBuilder.Statements) body.Statements.Add(statement); method.Body = body; return method; }
public override void TraverseChildren(IBlockStatement block) { base.TraverseChildren(block); Contract.Assume(block is BlockStatement); var decompiledBlock = (BlockStatement)block; var statements = decompiledBlock.Statements; for (int i = 0; i < statements.Count-1; i++) { //TODO: need to deal with patterns where the decl and the assignment are separated. var loclDecl = statements[i] as LocalDeclarationStatement; if (loclDecl == null) continue; var local = loclDecl.LocalVariable; if (local.Type.TypeCode != PrimitiveTypeCode.Boolean) continue; //if (this.sourceLocationProvider != null) { // bool isCompilerGenerated; // var sourceName = this.sourceLocationProvider.GetSourceNameFor(local, out isCompilerGenerated); // if (!isCompilerGenerated) continue; //} var tryFinallyStatement = statements[i+1] as TryCatchFinallyStatement; if (tryFinallyStatement == null) continue; if (tryFinallyStatement.FinallyBody == null || tryFinallyStatement.CatchClauses.Count > 0 || tryFinallyStatement.FaultBody != null) continue; ILocalDefinition monitorVar; var monitorObject = this.GetMonitor(tryFinallyStatement.TryBody, local, out monitorVar); if (monitorObject == null) continue; if (!this.FinallyBodyCallsMonitorExit(tryFinallyStatement.FinallyBody, local, monitorVar)) continue; this.numberOfAssignmentsToLocal[local]-=2; this.numberOfReferencesToLocal[local]-=2; this.numberOfAssignmentsToLocal[monitorVar]--; this.numberOfReferencesToLocal[monitorVar]--; var tryStatements = ((BlockStatement)tryFinallyStatement.TryBody).Statements; tryStatements.RemoveRange(0, 3); var body = new BlockStatement() { Statements = tryStatements }; var lockStatement = new LockStatement() { Guard = monitorObject, Body = body, Locations = tryFinallyStatement.Locations }; statements[i] = lockStatement; statements.RemoveAt(i+1); if (this.numberOfAssignmentsToLocal[monitorVar] == 0) { for (int j = 0; j < statements.Count; j++) { var ldecl = statements[j] as LocalDeclarationStatement; if (ldecl == null) continue; if (ldecl.LocalVariable != monitorVar) continue; statements.RemoveAt(j); break; } } } }
public static IBlockStatement GetRidOfStack(SourceMethodBody methodBody, IBlockStatement block) { var me = new Unstacker(methodBody); var result = me.Rewrite(block); var stmts = new List<IStatement>(); foreach (var loc in me.createdLocals.Values) { var decl = new LocalDeclarationStatement() { InitialValue = null, LocalVariable = loc, }; stmts.Add(decl); } stmts.AddRange(result.Statements); var newBlock = new BlockStatement() { Statements = stmts, Locations = new List<ILocation>(result.Locations), }; return newBlock; }
private bool ReplaceShortCircuitAnd2(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-3; i++) { var ifStatement = statements[i] as ConditionalStatement; if (ifStatement == null) continue; var gotoFalseCase = ifStatement.FalseBranch as GotoStatement; if (gotoFalseCase == null) continue; Contract.Assume(ifStatement.TrueBranch is EmptyStatement); var labeledStatement = statements[i+1] as LabeledStatement; if (labeledStatement == null) continue; var gotos = this.gotosThatTarget[(uint)labeledStatement.Label.UniqueKey]; if (gotos != null && gotos.Count > 0) continue; var ifStatement2 = statements[i+2] as ConditionalStatement; if (ifStatement2 == null) continue; var gotoTrueCase = ifStatement2.TrueBranch as GotoStatement; if (gotoTrueCase == null) continue; Contract.Assume(ifStatement2.FalseBranch is EmptyStatement); var labeledStatement2 = statements[i+3] as LabeledStatement; if (labeledStatement2 == null) continue; if (labeledStatement2 == gotoFalseCase.TargetStatement) { gotos = this.gotosThatTarget[(uint)labeledStatement2.Label.UniqueKey]; Contract.Assume(gotos != null && gotos.Count > 0); if (gotos.Count > 1) continue; var falseConst = new CompileTimeConstant() { Value = false, Type = this.host.PlatformType.SystemBoolean }; var conditional = new Conditional() { Condition = ifStatement.Condition, ResultIfTrue = ifStatement2.Condition, ResultIfFalse = falseConst, Type = this.host.PlatformType.SystemBoolean }; ifStatement2.Condition = conditional; statements.RemoveRange(i, 2); gotos.Remove(gotoFalseCase); replacedPattern = true; } else { if (gotoFalseCase.TargetStatement != gotoTrueCase.TargetStatement) continue; //actually have a short circuit or here gotos = this.gotosThatTarget[(uint)gotoFalseCase.TargetStatement.Label.UniqueKey]; Contract.Assume(gotos != null && gotos.Count > 0); var trueConst = new CompileTimeConstant() { Value = true, Type = this.host.PlatformType.SystemBoolean }; var invertedCond = new LogicalNot() { Operand = ifStatement.Condition, Type = this.host.PlatformType.SystemBoolean }; var conditional = new Conditional() { Condition = invertedCond, ResultIfTrue = trueConst, ResultIfFalse = ifStatement2.Condition, Type = this.host.PlatformType.SystemBoolean }; ifStatement2.Condition = conditional; statements.RemoveRange(i, 2); gotos.Remove(gotoFalseCase); replacedPattern = true; } } return replacedPattern; }
public override void RewriteChildren(BlockStatement blockStatement) { var savedCurrentBlockStatement = this.currentBlockStatement; this.currentBlockStatement = blockStatement; base.RewriteChildren(blockStatement); this.currentBlockStatement = savedCurrentBlockStatement; }
/// <summary> /// Rewrites the children of the given statement block. /// </summary> public override void RewriteChildren(BlockStatement block) { if (this.scopesWithCapturedLocals.ContainsKey(block)) { this.AllocateClosureFor(block, block.Statements, () => base.RewriteChildren(block)); } else base.RewriteChildren(block); }
public override void RewriteChildren(BlockStatement block) { base.RewriteChildren(block); if (this.localsToEliminate != null && this.localsToEliminate.Count > 0) { var statements = block.Statements; var n = statements.Count; var j = 0; for (int i = 0; i < n; i++) { var s = statements[i]; var localDecl = s as LocalDeclarationStatement; if (localDecl != null) { if (this.localsToEliminate.Contains(localDecl.LocalVariable)) continue; } else { var exprSt = s as ExpressionStatement; if (exprSt != null) { var assign = exprSt.Expression as Assignment; if (assign != null && this.localsToEliminate.Contains(assign.Target.Definition)) continue; } } statements[j++] = s; } if (j < n) statements.RemoveRange(j, n-j); } PatternReplacer.ReplacePushPopPattern(block, this.host); }
/// <summary> /// Inserts statements into block that will create an instance of the top level closure and initialize it /// with captured parameter values and the "this" value (if captured). /// </summary> private void InsertStatementsToAllocateAndInitializeTopLevelClosure(BlockStatement body) { List<IStatement> statements = new List<IStatement>(this.method.ParameterCount+2+body.Statements.Count); IFieldReference fieldReference; //initialize local with an instance of the closure class statements.Add( new LocalDeclarationStatement() { LocalVariable = this.currentClosureLocal, InitialValue = new CreateObjectInstance() { MethodToCall = this.GetReferenceToDefaultConstructor(this.currentClosureInstance), Type = this.currentClosureInstance } }); //initialize the fields of the closure class with the initial parameter values foreach (var parameter in this.method.Parameters) { if (!this.fieldReferencesForUseInsideThisMethod.TryGetValue(parameter, out fieldReference)) continue; statements.Add( new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Instance = this.currentClosureObject, Definition = fieldReference, Type = fieldReference.Type }, Source = new BoundExpression() { Definition = parameter, Type = parameter.Type }, Type = parameter.Type } }); } if (this.method.IsConstructor) { var offset = this.GetOffsetOfFirstStatementAfterBaseOrThisConstructorCall(body.Statements); statements.AddRange(body.Statements.GetRange(0, offset)); body.Statements.RemoveRange(0, offset); } //intialize the this argument field if that exists if (this.fieldReferencesForUseInsideThisMethod.TryGetValue(this.method, out fieldReference)) { statements.Add( new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Instance = this.currentClosureObject, Definition = fieldReference, Type = fieldReference.Type }, Source = new ThisReference() { Type = fieldReference.Type }, Type = fieldReference.Type } }); } statements.AddRange(body.Statements); body.Statements = statements; }
public override void BuildMethod() { AddStatement.DeclareInterceptedType(field.ContainingType.ResolvedType); Context.Log.WriteTrace(" Adding: var interceptedField = interceptedType.GetField('{0}');", field.Name.Value); Context.Block.Statements.Add( Declare.Variable<FieldInfo>("interceptedField").As( Call.VirtualMethod("GetField", typeof (string)).ThatReturns<FieldInfo>().WithArguments( Constant.Of(field.Name.Value)).On("interceptedType")) ); AddStatement.DeclareArgumentsList(); AddStatement.AddArgumentToList(Params["assignedValue"]); var actionT = SharpMockTypes.Actions[1]; var actionActualT = new GenericTypeInstanceReference(); actionActualT.GenericType = actionT; actionActualT.GenericArguments.Add(field.Type); var assignment = new AnonymousDelegate(); assignment.Type = actionActualT; assignment.ReturnType = Context.Host.PlatformType.SystemVoid; assignment.CallingConvention = CallingConvention.HasThis; var parameterDefinition = new ParameterDefinition(); parameterDefinition.Index = 0; parameterDefinition.Type = field.Type; parameterDefinition.Name = Context.Host.NameTable.GetNameFor("alteredValue"); parameterDefinition.ContainingSignature = assignment; assignment.Parameters.Add(parameterDefinition); var assignmentBody = new BlockStatement(); var assignActualField = new ExpressionStatement(); var actualField = new TargetExpression(); actualField.Type = field.Type; actualField.Definition = field; var value = new BoundExpression(); value.Type = field.Type; value.Definition = parameterDefinition; var assignValueToField = new Assignment(); assignValueToField.Source = value; assignValueToField.Target = actualField; assignValueToField.Type = field.Type; assignActualField.Expression = assignValueToField; actualField.Type = field.Type; actualField.Definition = field; assignmentBody.Statements.Add(assignActualField); assignmentBody.Statements.Add(new ReturnStatement()); assignment.Body = assignmentBody; Context.Block.Statements.Add( Declare.Variable("local_0", actionActualT).As(assignment) ); AddStatement.DeclareRegistryInterceptor(); AddStatement.DeclareInvocation(); AddStatement.SetArgumentsOnInvocation(); AddStatement.SetOriginalCallOnInvocation(); AddStatement.SetTargetOnInvocationToNull(); Context.Block.Statements.Add( Do(Call.PropertySetter<MemberInfo>("OriginalCallInfo").WithArguments("interceptedField").On("invocation")) ); AddStatement.CallShouldInterceptOnInterceptor(); AddStatement.CallInterceptOnInterceptor(); Context.Block.Statements.Add(Return.Void()); }
private bool ReplaceShortCircuitAnd4(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-2; i++) { var ifStatement1 = statements[i] as ConditionalStatement; if (ifStatement1 == null || !(ifStatement1.FalseBranch is EmptyStatement)) continue; var goto1 = ifStatement1.TrueBranch as GotoStatement; if (goto1 == null) continue; var labStat = statements[i+1] as LabeledStatement; if (labStat == null) continue; var gotos1 = this.gotosThatTarget[(uint)labStat.Label.UniqueKey]; if (gotos1 != null && gotos1.Count > 0) continue; var ifStatement2 = statements[i+2] as ConditionalStatement; if (ifStatement2 == null) continue; if (ifStatement2.TrueBranch is EmptyStatement) { var goto2 = ifStatement2.FalseBranch as GotoStatement; if (goto2 == null) continue; if (goto1.TargetStatement != goto2.TargetStatement) continue; var gotos = this.gotosThatTarget[(uint)goto1.TargetStatement.Label.UniqueKey]; if (gotos == null || gotos.Count == 0) continue; var falseConst = new CompileTimeConstant() { Value = false, Type = this.host.PlatformType.SystemBoolean }; var notCond1 = new LogicalNot() { Operand = ifStatement1.Condition, Type = this.host.PlatformType.SystemBoolean }; var conditional = new Conditional() { Condition = notCond1, ResultIfTrue = ifStatement2.Condition, ResultIfFalse = falseConst, Type = this.host.PlatformType.SystemBoolean }; ifStatement2.Condition = conditional; statements.RemoveRange(i, 2); gotos.Remove(goto1); replacedPattern = true; } else if (ifStatement2.FalseBranch is EmptyStatement) { var goto2 = ifStatement2.TrueBranch as GotoStatement; if (goto2 == null) continue; if (goto1.TargetStatement != goto2.TargetStatement) continue; var gotos = this.gotosThatTarget[(uint)goto1.TargetStatement.Label.UniqueKey]; if (gotos == null || gotos.Count == 0) continue; var trueConst = new CompileTimeConstant() { Value = true, Type = this.host.PlatformType.SystemBoolean }; var cond1 = ifStatement1.Condition; var conditional = new Conditional() { Condition = cond1, ResultIfTrue = trueConst, ResultIfFalse = ifStatement2.Condition, Type = this.host.PlatformType.SystemBoolean }; ifStatement2.Condition = conditional; statements.RemoveRange(i, 2); gotos.Remove(goto1); replacedPattern = true; } } return replacedPattern; }
private SourceMethodBody GetBody(IMethodDefinition method, IMethodReference originalCall) { var body = new SourceMethodBody(host, null, null); body.MethodDefinition = method; body.LocalsAreZeroed = true; var block = new BlockStatement(); body.Block = block; AddAlternativeInvocation(block, method, originalCall); return body; }
private bool ReplaceShortCircuitAnd5(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count; i++) { var ifStatement = statements[i] as ConditionalStatement; if (ifStatement == null) continue; var pushTrue = ifStatement.TrueBranch as IPushStatement; if (pushTrue == null) { var trueBlock = ifStatement.TrueBranch as BlockStatement; if (trueBlock != null && trueBlock.Statements.Count == 1) pushTrue = trueBlock.Statements[0] as IPushStatement; } if (pushTrue == null || pushTrue.ValueToPush.Type.TypeCode != PrimitiveTypeCode.Boolean) continue; var pushFalse = ifStatement.FalseBranch as IPushStatement; if (pushFalse == null) { var falseBlock = ifStatement.FalseBranch as BlockStatement; if (falseBlock != null && falseBlock.Statements.Count == 1) pushFalse = falseBlock.Statements[0] as IPushStatement; } if (pushFalse == null) continue; var falseCaseVal = pushFalse.ValueToPush as CompileTimeConstant; if (falseCaseVal == null || !(falseCaseVal.Value is int)) continue; if (0 != (int)falseCaseVal.Value) continue; var falseConst = new CompileTimeConstant() { Value = false, Type = this.host.PlatformType.SystemBoolean }; statements[i] = new PushStatement() { ValueToPush = new Conditional() { Condition = ifStatement.Condition, ResultIfTrue = pushTrue.ValueToPush, ResultIfFalse = falseConst, Type = pushTrue.ValueToPush.Type } }; replacedPattern = true; } return replacedPattern; }
private void injectNavigationUpdateCode(IBlockStatement block, IEnumerable <Tuple <IStatement, StaticURIMode, string> > staticStmts, IEnumerable <IStatement> nonStaticStmts) { // TODO Here there is the STRONG assumption that a given method will only navigate at most once per method call // TODO (or at most will re-navigate to the same page). Quick "page flipping" on the same method // TODO would not be captured correctly Microsoft.Cci.MutableCodeModel.BlockStatement mutableBlock = block as Microsoft.Cci.MutableCodeModel.BlockStatement; foreach (IStatement stmt in nonStaticStmts) { int ndx = mutableBlock.Statements.ToList().IndexOf(stmt); if (ndx == -1) { // can't be throw new IndexOutOfRangeException("Statement must exist in original block"); } Assignment currentURIAssign = new Assignment() { Source = new CompileTimeConstant() { Type = host.PlatformType.SystemString, Value = PhoneCodeHelper.BOOGIE_DO_HAVOC_CURRENTURI, }, Type = host.PlatformType.SystemString, Target = new TargetExpression() { Type = host.PlatformType.SystemString, // TODO unify code for current uri fieldreference Definition = new FieldReference() { ContainingType = PhoneCodeHelper.instance().getMainAppTypeReference(), IsStatic = true, Type = host.PlatformType.SystemString, Name = host.NameTable.GetNameFor(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE), InternFactory = host.InternFactory, }, }, }; Statement uriInitStmt = new ExpressionStatement() { Expression = currentURIAssign, }; mutableBlock.Statements.Insert(ndx + 1, uriInitStmt); } foreach (Tuple <IStatement, StaticURIMode, string> entry in staticStmts) { int ndx = mutableBlock.Statements.ToList().IndexOf(entry.Item1); if (ndx == -1) { // can't be throw new IndexOutOfRangeException("Statement must exist in original block"); } Assignment currentURIAssign = new Assignment() { Source = new CompileTimeConstant() { Type = host.PlatformType.SystemString, Value = UriHelper.getURIBase(entry.Item3).ToLower(), }, Type = host.PlatformType.SystemString, Target = new TargetExpression() { Type = host.PlatformType.SystemString, // TODO unify code for current uri fieldreference Definition = new FieldReference() { ContainingType = PhoneCodeHelper.instance().getMainAppTypeReference(), IsStatic = true, Type = host.PlatformType.SystemString, Name = host.NameTable.GetNameFor(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE), InternFactory = host.InternFactory, }, }, }; Statement uriInitStmt = new ExpressionStatement() { Expression = currentURIAssign, }; mutableBlock.Statements.Insert(ndx + 1, uriInitStmt); } }
private static void RemoveLastGoto(BlockStatement block) { Contract.Requires(block != null); var n = block.Statements.Count; if (n == 0) return; var lastStatement = block.Statements[n-1]; var lastGoto = lastStatement as GotoStatement; if (lastGoto != null) { block.Statements.RemoveAt(n-1); return; } var lastBlock = lastStatement as BlockStatement; if (lastBlock == null) return; RemoveLastGoto(lastBlock); }
/// <summary> /// When given a method definition and a block of statements that represents the Block property of the body of the method /// this method returns a semantically equivalent SourceMethod with a body that no longer has any anonymous delegate expressions. /// The given block of statements is mutated in place. /// Any types that get defined in order to implement the body semantics are returned (null if no such types are defined). /// </summary> /// <param name="method">The method containing the block that is to be rewritten.</param> /// <param name="body">The block to be rewritten. /// The entire tree rooted at the block must be mutable and the nodes must not be shared with anything else.</param> public ICollection<ITypeDefinition>/*?*/ RemoveAnonymousDelegates(IMethodDefinition method, BlockStatement body) { this.method = method; var finder = new CapturedParameterAndLocalFinder(); finder.TraverseChildren(body); this.fieldReferencesForUseInsideAnonymousMethods = finder.captures; this.anonymousDelegatesThatCaptureLocalsOrParameters = finder.anonymousDelegatesThatCaptureLocalsOrParameters; this.anonymousDelegatesThatCaptureThis = finder.anonymousDelegatesThatCaptureThis; finder = null; var blockFinder = new ScopesWithCapturedLocalsFinder(this.fieldReferencesForUseInsideAnonymousMethods); blockFinder.TraverseChildren(body); this.scopesWithCapturedLocals = blockFinder.scopesWithCapturedLocals; blockFinder = null; this.fieldReferencesForUseInsideThisMethod = new Dictionary<object, IFieldReference>(this.fieldReferencesForUseInsideAnonymousMethods); this.GenerateTopLevelClosure(); if (this.currentClosureClass != null) { //declare a local to keep the parameter closure class var closureLocal = new LocalDefinition() { Type = this.currentClosureInstance, Name = this.host.NameTable.GetNameFor("CS$<>8__locals"+this.closureClasses.Count) }; this.currentClosureLocal = closureLocal; this.currentClosureObject = new BoundExpression() { Definition = closureLocal, Type = closureLocal.Type }; this.closureLocalInstances = new List<IExpression>(); this.closureLocalInstances.Add(this.currentClosureObject); this.scopesWithCapturedLocals.Remove(body); //otherwise it will introduce its own closure class if any of its locals were captured. this.RewriteChildren(body); //do this after rewriting so that parameter references are not rewritten into closure field references. this.InsertStatementsToAllocateAndInitializeTopLevelClosure(body); } else { this.RewriteChildren(body); } return this.closureClasses == null ? null : this.closureClasses.AsReadOnly(); }
private static GotoStatement/*?*/ ReturnLastGoto(BlockStatement block) { Contract.Requires(block != null); var n = block.Statements.Count; if (n == 0) return null; var lastStatement = block.Statements[n-1]; var lastGoto = lastStatement as GotoStatement; if (lastGoto != null) return lastGoto; var lastBlock = lastStatement as BlockStatement; if (lastBlock == null) return null; return ReturnLastGoto(lastBlock); }
/// <summary> /// Creates a new nested type definition with a default constructor and no other members and adds it to this.closureClasses. /// If this.method is generic, then the closure class is generic as well, with the same /// number of type parameters (constrained in the same way) as the generic method. /// Initializes this.currentClosure, this.currentClosureInstance and this.currentClosureSelfInstance. /// </summary> private void CreateClosureClass() { if (this.closureClasses == null) this.closureClasses = new List<ITypeDefinition>(); NestedTypeDefinition closure = new NestedTypeDefinition(); var containingType = this.method.ContainingTypeDefinition; closure.Name = this.host.NameTable.GetNameFor("<"+this.method.Name+">c__DisplayClass"+closure.GetHashCode()); closure.Attributes = new List<ICustomAttribute>(1) { this.compilerGenerated }; closure.BaseClasses = new List<ITypeReference>(1) { this.host.PlatformType.SystemObject }; closure.ContainingTypeDefinition = containingType; closure.Fields = new List<IFieldDefinition>(); closure.InternFactory = this.host.InternFactory; closure.IsBeforeFieldInit = true; closure.IsClass = true; closure.IsSealed = true; closure.Layout = LayoutKind.Auto; closure.Methods = new List<IMethodDefinition>(); closure.StringFormat = StringFormatKind.Ansi; closure.Visibility = TypeMemberVisibility.Private; this.closureClasses.Add(closure); this.currentClosureClass = closure; //generics if (this.method.IsGeneric) { Dictionary<ushort, IGenericParameterReference> genericMethodParameterMap = new Dictionary<ushort, IGenericParameterReference>(); this.genericMethodParameterMap = genericMethodParameterMap; bool foundConstraints = false; var genericTypeParameters = new List<IGenericTypeParameter>(this.method.GenericParameterCount); closure.GenericParameters = genericTypeParameters; foreach (var genericMethodParameter in this.method.GenericParameters) { var copyOfGenericMethodParameter = this.copier.Copy(genericMethodParameter); //so that we have mutable constraints to rewrite var genericTypeParameter = new GenericTypeParameter(); genericTypeParameter.Copy(copyOfGenericMethodParameter, this.host.InternFactory); genericTypeParameter.DefiningType = closure; if (genericTypeParameter.Constraints != null && genericTypeParameter.Constraints.Count > 0) foundConstraints = true; genericTypeParameters.Add(genericTypeParameter); genericMethodParameterMap.Add(copyOfGenericMethodParameter.Index, genericTypeParameter); } if (foundConstraints) { //Fix up any self references that might lurk inside constraints. closure.GenericParameters = new GenericParameterRewriter(this.host, genericMethodParameterMap).Rewrite(genericTypeParameters); } var instanceType = closure.InstanceType; var genericArguments = IteratorHelper.GetConversionEnumerable<IGenericMethodParameter, ITypeReference>(this.method.GenericParameters); this.currentClosureInstance = new Immutable.GenericTypeInstanceReference(instanceType.GenericType, genericArguments, this.host.InternFactory); this.currentClosureSelfInstance = instanceType; } else { //if any of the containing types are generic, we need an instance or a specialized nested type. this.currentClosureInstance = NestedTypeDefinition.SelfInstance(closure, this.host.InternFactory); this.currentClosureSelfInstance = this.currentClosureInstance; } //default constructor var block = new BlockStatement(); block.Statements.Add( new ExpressionStatement() { Expression = new MethodCall() { ThisArgument = new ThisReference() { Type = this.currentClosureSelfInstance }, MethodToCall = this.objectCtor, Type = this.host.PlatformType.SystemVoid } } ); var constructorBody = new SourceMethodBody(this.host, this.sourceLocationProvider) { LocalsAreZeroed = true, IsNormalized = true, Block = block }; var defaultConstructor = new MethodDefinition() { Body = constructorBody, ContainingTypeDefinition = closure, CallingConvention = CallingConvention.HasThis, InternFactory = this.host.InternFactory, IsCil = true, IsHiddenBySignature = true, IsRuntimeSpecial = true, IsSpecialName = true, Name = this.host.NameTable.Ctor, Type = this.host.PlatformType.SystemVoid, Visibility = TypeMemberVisibility.Public, }; constructorBody.MethodDefinition = defaultConstructor; closure.Methods.Add(defaultConstructor); }
/// <summary> /// Visits the specified block. /// </summary> /// <param name="block">The block.</param> public override void Visit(IBlockStatement block) { BlockStatement mutableBlockStatement = new BlockStatement(block); this.resultStatement = this.myCodeCopier.DeepCopy(mutableBlockStatement); }
/// <summary> /// Rewrites the given assignment expression. /// </summary> public override IExpression Rewrite(IAssignment assignment) { var targetInstance = assignment.Target.Instance; var result = base.Rewrite(assignment); if (targetInstance == null && assignment.Target.Instance != null) { //The target now pushes something onto the stack that was not there before the rewrite. //It the right hand side uses the stack, then it will not see the stack it expected. //If so, we need to evaluate the right handside and squirrel it away in a temp before executing //the actual assignment. var popFinder = new PopFinder(); popFinder.Traverse(assignment.Source); if (popFinder.foundAPop) { var temp = new LocalDefinition() { Name = this.host.NameTable.GetNameFor("PopTemp"+this.popTempCounter++), Type = assignment.Source.Type }; var localDeclarationStatement = new LocalDeclarationStatement() { LocalVariable = temp, InitialValue = assignment.Source }; var blockStatement = new BlockStatement(); blockStatement.Statements.Add(localDeclarationStatement); Contract.Assume(assignment is Assignment); ((Assignment)assignment).Source = new BoundExpression() { Definition = temp, Type = temp.Type }; return new BlockExpression() { BlockStatement = blockStatement, Expression = assignment, Type = assignment.Type }; } } return result; }
/// <summary> /// Visits the specified block statement. /// </summary> /// <param name="blockStatement">The block statement.</param> /// <returns></returns> protected virtual IBlockStatement DeepCopy(BlockStatement blockStatement) { blockStatement.Statements = Substitute(blockStatement.Statements); return blockStatement; }
private IBlockStatement DuplicateMoveNextForIteratorMethod(BlockStatement rootBlock) { return MoveNextToIteratorBlockTransformer.Transform(iteratorMethodBody.MethodDefinition, this.ilMethodBody.MethodDefinition, rootBlock, this.host); }
public static IBlockStatement MkBlockStatement(IStatement statement) { var block = statement as IBlockStatement; if (block == null) { block = new BlockStatement() { Statements = new List<IStatement> { statement }, }; } return block; }