private ILabeledStatement GetTargetStatement(uint offset) { LabeledStatement result = this.targetStatementFor[offset]; if (result != null) return result; var labeledStatement = new LabeledStatement(); labeledStatement.Label = this.nameTable.GetNameFor("IL_" + offset.ToString("x4")); labeledStatement.Statement = new EmptyStatement(); this.targetStatementFor.Add(offset, labeledStatement); return labeledStatement; }
/// <summary> /// Visits the specified labeled statement. /// </summary> /// <param name="labeledStatement">The labeled statement.</param> public override void Visit(ILabeledStatement labeledStatement) { LabeledStatement mutableLabeledStatement = new LabeledStatement(labeledStatement); this.resultStatement = this.myCodeCopier.DeepCopy(mutableLabeledStatement); }
/// <summary> /// Visits the specified labeled statement. /// </summary> /// <param name="labeledStatement">The labeled statement.</param> /// <returns></returns> protected virtual IStatement DeepCopy(LabeledStatement labeledStatement) { labeledStatement.Statement = Substitute(labeledStatement.Statement); return labeledStatement; }
public override void TraverseChildren(IBlockStatement block) { Contract.Assume(block is BlockStatement); var decompiledBlock = (BlockStatement)block; var statements = decompiledBlock.Statements; for (int i = 0; i < statements.Count; i++) { var statement = statements[i]; var conditionalStatement = statement as ConditionalStatement; if (conditionalStatement == null) continue; var condition = conditionalStatement.Condition; var gotoStatement = conditionalStatement.FalseBranch as GotoStatement; if (gotoStatement == null) { gotoStatement = conditionalStatement.TrueBranch as GotoStatement; if (gotoStatement == null) continue; if (!(conditionalStatement.FalseBranch is EmptyStatement)) continue; condition = InvertCondition(condition); } else { if (!(conditionalStatement.TrueBranch is EmptyStatement)) continue; } var gotosThatTarget = this.gotosThatTarget[(uint)gotoStatement.TargetStatement.Label.UniqueKey]; Contract.Assume(gotosThatTarget != null && gotosThatTarget.Count > 0); var trueBlock = ExtractBlock(statements, i+1, gotoStatement.TargetStatement, gotosThatTarget.Count == 1); if (trueBlock == null) continue; if (conditionalStatement.TrueBranch is EmptyStatement) conditionalStatement.FalseBranch = conditionalStatement.TrueBranch; conditionalStatement.TrueBranch = trueBlock; conditionalStatement.Condition = condition; gotosThatTarget.Remove(gotoStatement); } for (int i = statements.Count-2; i >= 0; i--) { Contract.Assume(i < statements.Count); var statement = statements[i]; var conditionalStatement = statement as ConditionalStatement; if (conditionalStatement == null || !(conditionalStatement.FalseBranch is EmptyStatement)) continue; var trueBlock = conditionalStatement.TrueBranch as BlockStatement; if (trueBlock == null) continue; var gotoEndif = ReturnLastGoto(trueBlock); if (gotoEndif == null) continue; var gotosThatTarget = this.gotosThatTarget[(uint)gotoEndif.TargetStatement.Label.UniqueKey]; Contract.Assume(gotosThatTarget != null && gotosThatTarget.Count > 0); var falseBlock = ExtractBlock(statements, i+1, gotoEndif.TargetStatement, gotosThatTarget.Count == 1); if (falseBlock == null) continue; conditionalStatement.FalseBranch = falseBlock; gotosThatTarget.Remove(gotoEndif); RemoveLastGoto(trueBlock); } var savedLabelImmediatelyFollowingCurrentBlock = this.labelImmediatelyFollowingCurrentBlock; for (int i = 0, n = decompiledBlock.Statements.Count; i < n; i++) { var statement = decompiledBlock.Statements[i]; Contract.Assume(statement != null); if (statement is BlockStatement || statement is ConditionalStatement) { if (i < n-1) { this.labelImmediatelyFollowingCurrentBlock = decompiledBlock.Statements[i+1] as LabeledStatement; if (this.labelImmediatelyFollowingCurrentBlock == null) { var blk = decompiledBlock.Statements[i+1] as BlockStatement; if (blk != null && blk.Statements.Count > 0) this.labelImmediatelyFollowingCurrentBlock = blk.Statements[0] as LabeledStatement; } } else { this.labelImmediatelyFollowingCurrentBlock = savedLabelImmediatelyFollowingCurrentBlock; } } this.Traverse(statement); } this.labelImmediatelyFollowingCurrentBlock = savedLabelImmediatelyFollowingCurrentBlock; }
internal void ReplaceInitialLabel(LabeledStatement labeledStatement) { Contract.Requires(labeledStatement != null); for (int i = 0, n = this.Statements.Count; i < n; i++) { var s = this.Statements[i]; var ls = s as LabeledStatement; if (ls != null) { this.Statements[i] = labeledStatement; return; } var b = s as DecompiledBlock; if (b != null) b.ReplaceInitialLabel(labeledStatement); var d = s as LocalDeclarationStatement; if (d != null && d.InitialValue == null) continue; break; } }
/// <summary> /// Rewrites the children of the given labeled statement. /// </summary> public virtual void RewriteChildren(LabeledStatement labeledStatement) { this.RewriteChildren((Statement)labeledStatement); labeledStatement.Statement = this.Rewrite(labeledStatement.Statement); }
public override void TraverseChildren(IBlockStatement block) { Contract.Assume(block is BlockStatement); var b = (BlockStatement)block; var savedLabelImmediatelyFollowingCurrentBlock = this.labelImmediatelyFollowingCurrentBlock; for (int i = 0, n = b.Statements.Count; i < n; i++) { var statement = b.Statements[i]; Contract.Assume(statement != null); if (statement is BlockStatement) { if (i < n-1) { this.labelImmediatelyFollowingCurrentBlock = b.Statements[i+1] as LabeledStatement; if (this.labelImmediatelyFollowingCurrentBlock == null) { var blk = b.Statements[i+1] as BlockStatement; if (blk != null && blk.Statements.Count > 0) this.labelImmediatelyFollowingCurrentBlock = blk.Statements[0] as LabeledStatement; } } else { this.labelImmediatelyFollowingCurrentBlock = savedLabelImmediatelyFollowingCurrentBlock; } } this.Traverse(statement); } this.labelImmediatelyFollowingCurrentBlock = savedLabelImmediatelyFollowingCurrentBlock; while (this.ReplaceArrayInitializerPattern(b) || this.ReplaceArrayInitializerPattern2(b) || this.ReplaceConditionalExpressionPattern(b) || this.ReplacePushPushDupPopPopPattern(b) || this.ReplacePushDupPopPattern(b) || this.ReplacePushDupPushPopPattern(b) || ReplacePushPopPattern(b, this.host) || this.ReplaceDupPopPattern(b) || this.ReplacePostBinopPattern(b) || this.ReplacePropertyBinopPattern(b) || this.ReplaceReturnViaGoto(b) || this.ReplaceReturnViaGotoInVoidMethods(b) || this.ReplaceSelfAssignment(b) || this.ReplaceShortCircuitAnd(b) || this.ReplaceShortCircuitAnd2(b) || this.ReplaceShortCircuitAnd3(b) || this.ReplaceShortCircuitAnd4(b) || this.ReplaceShortCircuitAnd5(b) || this.ReplaceShortCircuitAnd6(b) || this.ReplacedCompoundAssignmentViaTempPattern(b) || this.ReplaceSingleUseCompilerGeneratedLocalPattern(b) || this.ReplaceCompilerGeneratedLocalUsedForInitializersPattern(b) || this.ReplacePlusAssignForStringPattern(b) ) { } //Look for a final return that returns a temp that is never assigned to. //Assuming the compiler did not allow unitialized variables, this return should be an unreachable compiler artifact. if (b == this.finalBlock) { var n = b.Statements.Count; Contract.Assume(n >= 2 && this.returnValueTemp != null); int statementsToRemove = 2; var labeledStatement = b.Statements[n-2] as LabeledStatement; if (labeledStatement == null && n >= 3 && b.Statements[n-2] is EmptyStatement) { labeledStatement = b.Statements[n-3] as LabeledStatement; statementsToRemove = 3; } var returnStatement = b.Statements[n-1] as ReturnStatement; Contract.Assume(labeledStatement != null && returnStatement != null); var boundExpression = returnStatement.Expression as BoundExpression; Contract.Assume(boundExpression != null); Contract.Assume(this.returnValueTemp == boundExpression.Definition); if (this.numberOfAssignmentsToLocal[this.returnValueTemp] == 0) { //Contract.Assume(this.numberOfReferencesToLocal[this.returnValueTemp] == 1); this.labelOfFinalReturn = labeledStatement.Label; for (int i = 0; i < n; i++) { var localDeclarationStatement = b.Statements[i] as LocalDeclarationStatement; if (localDeclarationStatement == null) return; if (localDeclarationStatement.LocalVariable != this.returnValueTemp) continue; b.Statements.RemoveAt(i); n--; break; } Contract.Assume(n >= statementsToRemove); b.Statements.RemoveRange(n-statementsToRemove, statementsToRemove); } } }
/// <summary> /// Replace a (yield return exp)with a new block of the form: /// { /// Fresh_Label:; /// this.current = exp; /// state = Fresh_state; /// return true; /// } /// and associate the newly generated Fresh_state with its entry point: Fresh_label. /// </summary> public override IStatement Rewrite(IYieldReturnStatement yieldReturnStatement) { BlockStatement blockStatement = new BlockStatement(); int state = this.stateNumber++; ExpressionStatement thisDotStateEqState = new ExpressionStatement() { Expression = new Assignment() { Source = new CompileTimeConstant() { Value = state, Type = this.host.PlatformType.SystemInt32 }, Target = new TargetExpression() { Definition = this.iteratorClosure.StateFieldReference, Instance = new ThisReference(), Type = this.host.PlatformType.SystemInt32 }, Type = this.host.PlatformType.SystemInt32, }, Locations = IteratorHelper.EnumerableIsEmpty(yieldReturnStatement.Locations) ? null : new List<ILocation>(yieldReturnStatement.Locations) }; blockStatement.Statements.Add(thisDotStateEqState); ExpressionStatement thisDotCurrentEqReturnExp = new ExpressionStatement() { Expression = new Assignment() { Source = yieldReturnStatement.Expression, Target = new TargetExpression() { Definition = this.iteratorClosure.CurrentFieldReference, Instance = new ThisReference(), Type = this.iteratorClosure.CurrentFieldReference.Type }, Type = this.iteratorClosure.CurrentFieldReference.Type } }; blockStatement.Statements.Add(thisDotCurrentEqReturnExp); ReturnStatement returnTrue = new ReturnStatement() { Expression = new CompileTimeConstant() { Value = true, Type = this.host.PlatformType.SystemBoolean } }; blockStatement.Statements.Add(returnTrue); LabeledStatement labeledStatement = new LabeledStatement() { Label = this.host.NameTable.GetNameFor("Label"+state), Statement = new EmptyStatement() }; blockStatement.Statements.Add(labeledStatement); this.stateEntries.Add(state, labeledStatement); return blockStatement; }
/// <summary> /// Build the state machine. /// /// We start from state 0. For each yield return, we assign a unique state, which we call continueing state. For a yield return /// assigned with state x, we move the state machine from the previous state to x. Whenever we see a yield break, we transit /// the state to -1. /// /// When we return from state x, we jump to a label that is inserted right after the previous yield return (that is assigned with state x). /// </summary> private BlockStatement BuildStateMachine(IteratorClosureInformation iteratorClosure, BlockStatement oldBody, Dictionary<int, ILabeledStatement> stateEntries) { // Switch on cases. StateEntries, which have been computed previously, map a state number (for initial and continuing states) to a label that has been inserted // right after the associated yield return. BlockStatement result = new BlockStatement(); var returnFalse = new ReturnStatement() { Expression = new CompileTimeConstant() { Value = false, Type = this.host.PlatformType.SystemBoolean } }; var returnFalseLabel = new LabeledStatement() { Label = this.host.NameTable.GetNameFor("return false"), Statement = returnFalse }; List<ISwitchCase> cases = new List<ISwitchCase>(); foreach (int i in stateEntries.Keys) { SwitchCase c = new SwitchCase() { Expression = new CompileTimeConstant() { Type = this.host.PlatformType.SystemInt32, Value = i }, Body = new List<IStatement>(), }; c.Body.Add(new GotoStatement() { TargetStatement = stateEntries[i] }); cases.Add(c); } // Default case. SwitchCase defaultCase = new SwitchCase(); defaultCase.Body.Add(new GotoStatement() { TargetStatement = returnFalseLabel }); cases.Add(defaultCase); SwitchStatement switchStatement = new SwitchStatement() { Cases = cases, Expression = new BoundExpression() { Type = this.host.PlatformType.SystemInt32, Instance = new ThisReference(), Definition = iteratorClosure.StateFieldReference } }; result.Statements.Add(switchStatement); result.Statements.Add(oldBody); result.Statements.Add(returnFalseLabel); return result; }
public override void TraverseChildren(IBlockStatement block) { Contract.Assume(block is BlockStatement); var decompiledBlock = (BlockStatement)block; var statements = decompiledBlock.Statements; List<IStatement> newStatements = null; for (int i = 0, n = statements.Count; i < n; i++) { LabeledStatement outerLabel = null; Contract.Assume(i < statements.Count); var statement = statements[i]; Contract.Assume(statement != null); var nestedBlock = statement as DecompiledBlock; if (nestedBlock != null) { var trycf = this.tryCatchFinallyMap.Find(nestedBlock.StartOffset, nestedBlock.EndOffset); if (trycf != null) { statements[i] = trycf; if (newStatements == null) newStatements = CopyStatements(statements, i); IOperationExceptionInformation handlerInfo = this.handlerMap.Find(nestedBlock.StartOffset, nestedBlock.EndOffset); if (handlerInfo == null) { outerLabel = nestedBlock.ReturnInitialLabel(); if (outerLabel != null) { newStatements.Add(outerLabel); var innerLabel = new LabeledStatement(outerLabel); innerLabel.Label = this.host.NameTable.GetNameFor(outerLabel.Label.Value+"#inner"); nestedBlock.ReplaceInitialLabel(innerLabel); this.trystartOutsideLabels.Add(outerLabel); this.insideLabelFor[(uint)outerLabel.Label.UniqueKey] = innerLabel; } trycf.TryBody = nestedBlock; statement = trycf; } else { switch (handlerInfo.HandlerKind) { case HandlerKind.Catch: ILocalDefinition exceptionContainer = this.ExtractExceptionContainer(nestedBlock, handlerInfo.ExceptionType); if (!(exceptionContainer is Dummy)) this.RemoveLocalDeclarationOf(exceptionContainer, nestedBlock); trycf.CatchClauses.Add(new CatchClause() { Body = nestedBlock, ExceptionType = handlerInfo.ExceptionType, ExceptionContainer = exceptionContainer }); break; case HandlerKind.Fault: trycf.FaultBody = nestedBlock; break; case HandlerKind.Filter: var filterCondition = this.GetFilterCondition(nestedBlock); if (filterCondition != null) this.RemovedFilterCondition(nestedBlock); trycf.CatchClauses.Add(new CatchClause() { Body = nestedBlock, ExceptionType = this.host.PlatformType.SystemObject, FilterCondition = filterCondition }); break; case HandlerKind.Finally: this.RemoveEndFinallyFrom(nestedBlock); trycf.FinallyBody = nestedBlock; break; } this.Traverse(nestedBlock); if (outerLabel != null) this.trystartOutsideLabels.Remove(outerLabel); continue; } } } if (newStatements != null) newStatements.Add(statement); this.Traverse(statement); } if (newStatements != null) { decompiledBlock.Statements = newStatements; for (int i = 0, n = newStatements.Count-1; i < n; i++) { var trycf = newStatements[i] as TryCatchFinallyStatement; if (trycf == null) continue; var followingBlock = newStatements[i+1] as DecompiledBlock; if (followingBlock != null) this.RemoveUnconditionalBranchesToLabelImmediatelyFollowing(trycf, followingBlock); this.ConsolidateScopes(trycf); } } }
/// <summary> /// Compute the mapping between every (starting and continuing) state and their unique entry points. It does so /// by inserting a unique label at the entry points and associate the state with the label. /// </summary> internal Dictionary<int, ILabeledStatement> GetStateEntries(BlockStatement body) { BlockStatement blockStatement = body; stateEntries = new Dictionary<int, ILabeledStatement>(); LabeledStatement initialLabel = new LabeledStatement() { Label = this.host.NameTable.GetNameFor("Label"+ this.stateNumber++), Statement = new EmptyStatement() }; // O(n), but happen only once. blockStatement.Statements.Insert(0, initialLabel); stateEntries.Add(0, initialLabel); this.stateNumber = 1; this.RewriteChildren(blockStatement); this.stateNumber = 0; Dictionary<int, ILabeledStatement> result = stateEntries; stateEntries = null; return result; }
private bool RemoveEndFinallyFrom(DecompiledBlock block, LabeledStatement labelToGoto) { Contract.Requires(block != null); Contract.Requires(labelToGoto != null); for (int i = 0; i < block.Statements.Count; i++) { if (block.Statements[i] is EndFinally) { var gotoFinally = new GotoStatement() { TargetStatement = labelToGoto }; block.Statements[i] = gotoFinally; var gotos = new List<IGotoStatement>(1); gotos.Add(gotoFinally); this.gotosThatTarget[(uint)labelToGoto.Label.UniqueKey] = gotos; return true; } var nestedBlock = block.Statements[i] as DecompiledBlock; if (nestedBlock != null && this.RemoveEndFinallyFrom(nestedBlock, labelToGoto)) return true; } return false; }
private bool RemoveEndFinallyFrom(DecompiledBlock block) { Contract.Requires(block != null); Contract.Assume(block.Statements.Count > 0); //There must be an endfinally if (block.Statements[block.Statements.Count-1] is EndFinally) { block.Statements.RemoveAt(block.Statements.Count-1); return true; } var lastBlock = block.Statements[block.Statements.Count-1] as DecompiledBlock; if (lastBlock != null && this.RemoveEndFinallyFrom(lastBlock)) return true; LabeledStatement endFinally = new LabeledStatement() { Label = this.host.NameTable.GetNameFor("__endfinally#"+this.endFinallyCounter++), Statement = new EmptyStatement() }; block.Statements.Add(endFinally); return this.RemoveEndFinallyFrom(block, endFinally); }
/// <summary> /// Visits the specified labeled statement. /// </summary> /// <param name="labeledStatement">The labeled statement.</param> /// <returns></returns> public virtual IStatement Visit(LabeledStatement labeledStatement) { labeledStatement.Statement = Visit(labeledStatement.Statement); return labeledStatement; }
delegate void Action(); //not defined in CLR v2. /// <summary> /// Saves the current closure fields. Allocates a new closure and updates the fields. Then calls the given delegate and /// restores the earlier state. /// </summary> private void AllocateClosureFor(object scope, List<IStatement> statements, Action rewriteScope) { Contract.Assume(!this.isInsideAnonymousMethod); var savedCurrentClosure = this.currentClosureClass; var savedCurrentClosureSelfInstance = this.currentClosureSelfInstance; var savedCurrentClosureInstance = this.currentClosureInstance; var savedCurrentClosureObject = this.currentClosureObject; var savedCurrentClosureLocal = this.currentClosureLocal; this.CreateClosureClass(); IFieldReference outerClosure = null; if (savedCurrentClosureLocal != null) { this.CreateClosureField(this.currentClosureSelfInstance, savedCurrentClosureSelfInstance, savedCurrentClosureInstance, savedCurrentClosureLocal.Name.Value); outerClosure = this.fieldReferencesForUseInsideThisMethod[this.currentClosureSelfInstance]; } var closureLocal = new LocalDefinition() { Type = this.currentClosureInstance, Name = this.host.NameTable.GetNameFor("CS$<>__locals"+this.closureClasses.Count) }; this.currentClosureObject = new BoundExpression() { Definition = closureLocal, Type = this.currentClosureInstance }; this.currentClosureLocal = closureLocal; if (this.closureLocalInstances == null) this.closureLocalInstances = new List<IExpression>(); this.closureLocalInstances.Add(this.currentClosureObject); rewriteScope(); Statement createClosure = new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Definition = closureLocal, Type = closureLocal.Type }, Source = new CreateObjectInstance() { MethodToCall = this.GetReferenceToDefaultConstructor(this.currentClosureInstance), Type = currentClosureSelfInstance, } } }; ILabeledStatement labeledStatement = null; for (int i = 0, n = statements.Count; i < n; i++) { labeledStatement = statements[i] as ILabeledStatement; if (labeledStatement != null) { createClosure = new LabeledStatement() { Label = labeledStatement.Label, Statement = createClosure }; createClosure.Locations.AddRange(labeledStatement.Locations); statements[i] = labeledStatement.Statement; break; } else if (statements[i] is IEmptyStatement) { continue; } else { var declSt = statements[i] as ILocalDeclarationStatement; if (declSt != null && declSt.InitialValue == null) continue; break; } } statements.Insert(0, createClosure); if (outerClosure != null) { statements.Insert(1, new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Instance = new BoundExpression() { Definition = closureLocal, Type = closureLocal.Type }, Definition = outerClosure, Type = closureLocal.Type }, Source = new BoundExpression() { Definition = savedCurrentClosureLocal, Type = savedCurrentClosureLocal.Type }, Type = closureLocal.Type, } }); } this.currentClosureClass = savedCurrentClosure; this.currentClosureSelfInstance = savedCurrentClosureSelfInstance; this.currentClosureInstance = savedCurrentClosureInstance; this.currentClosureObject = savedCurrentClosureObject; this.currentClosureLocal = savedCurrentClosureLocal; }
public override IStatement Visit(LabeledStatement labeledStatement) { if (!this.referencedLabels.ContainsKey(labeledStatement.Label.UniqueKey)) return CodeDummy.Block; return base.Visit(labeledStatement); }
/// <summary> /// /// </summary> /// <param name="offset"></param> /// <param name="addLabel"></param> /// <returns></returns> protected BasicBlock GetOrCreateBlock(uint offset, bool addLabel) { BasicBlock result; if (!this.blockFor.TryGetValue(offset, out result)) { result = new BasicBlock(offset); this.blockFor.Add(offset, result); } if (addLabel && result.Statements.Count == 0) { LabeledStatement label = new LabeledStatement(); label.Label = this.nameTable.GetNameFor("IL_" + offset.ToString("x4")); label.Statement = new EmptyStatement(); result.Statements.Add(label); this.targetStatementFor.Add(offset, label); } return result; }
/// <summary> /// Visits the specified labeled statement. /// </summary> /// <param name="labeledStatement">The labeled statement.</param> public override void Visit(ILabeledStatement labeledStatement) { LabeledStatement mutableLabeledStatement = labeledStatement as LabeledStatement; if (alwaysMakeACopy || mutableLabeledStatement == null) mutableLabeledStatement = new LabeledStatement(labeledStatement); this.resultStatement = this.myCodeMutator.Visit(mutableLabeledStatement); }