void ScanLine(YieldVMStat vm, int start, int stop) { int m = start; while (m < stop) { ILNode node = vm.usefulList [m]; bool skipNode = false; bool jumpped = false; if (node is ILExpression) { ILExpression expr = node as ILExpression; if (expr.Code == ILCode.Switch) { int pendingSwitchExprJumpLableIndex = -1; bool isStateSwithPending = false; int finalStatVal = 0; if (expr.Arguments [0].Code == ILCode.Ldloc && expr.Arguments [0].Operand == vm.statILVariable) { isStateSwithPending = true; pendingSwitchExprJumpLableIndex = vm.localStat; finalStatVal = vm.localStat; } else if (expr.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (expr.Arguments [0].Operand as FieldReference) == this.stateField) { isStateSwithPending = true; pendingSwitchExprJumpLableIndex = vm.fieldStat; finalStatVal = vm.fieldStat; } else if (expr.Arguments [0].Code == ILCode.Sub) { ILExpression iLExpression10 = expr.Arguments [0]; if (iLExpression10.Arguments [0].Code == ILCode.Ldloc && iLExpression10.Arguments [0].Operand == vm.statILVariable) { if (iLExpression10.Arguments [1].Code == ILCode.Ldc_I4) { finalStatVal = vm.localStat; pendingSwitchExprJumpLableIndex = vm.localStat - (int)iLExpression10.Arguments [1].Operand; isStateSwithPending = true; } } else if (iLExpression10.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (iLExpression10.Arguments [0].Operand as FieldReference) == this.stateField) { if (iLExpression10.Arguments [1].Code == ILCode.Ldc_I4) { finalStatVal = vm.fieldStat; pendingSwitchExprJumpLableIndex = vm.fieldStat - (int)iLExpression10.Arguments [1].Operand; isStateSwithPending = true; } } } if (isStateSwithPending) { ILLabel jmpLabel = null; ILLabel[] lbList = expr.Operand as ILLabel[]; if (pendingSwitchExprJumpLableIndex >= 0 && pendingSwitchExprJumpLableIndex < lbList.Length) { jmpLabel = lbList [pendingSwitchExprJumpLableIndex]; } else { if (m + 1 >= vm.usefulList.Count || !(vm.usefulList [m + 1] is ILExpression) || (vm.usefulList [m + 1] as ILExpression).Code != ILCode.Br) { //impossible throw new SymbolicAnalysisFailedException (); } ILExpression switchDefault = vm.usefulList [m + 1] as ILExpression; jmpLabel = switchDefault.Operand as ILLabel; } //convert switch to jmp if (pendingSwitchExprJumpLableIndex >= 0 && pendingSwitchExprJumpLableIndex < lbList.Length) { bool addedJump = false; if (expr == vm.firstStatSwitchExpr) { addedJump = vm.addNewNode (new ILExpression (ILCode.Br, jmpLabel), m); if (!addedJump && vm.fieldStatChangedPos.ContainsKey (finalStatVal)) { int stateStartPos = vm.fieldStatChangedPos [finalStatVal]; addedJump = vm.addNewNode (new ILExpression (ILCode.Br, jmpLabel), stateStartPos); } vm.localStatChangedPos.Clear (); } else { if (vm.localStatChangedPos.ContainsKey (finalStatVal)) { int stateStartPos = vm.localStatChangedPos [finalStatVal]; addedJump = vm.addNewNode (new ILExpression (ILCode.Br, jmpLabel), stateStartPos); if (!addedJump) { if (!vm.addNewNode(new ILExpression(ILCode.Br, jmpLabel), m)) { //throw new SymbolicAnalysisFailedException (); } } } } } else { vm.addNewNode (new ILExpression (ILCode.Br, jmpLabel), m ); } vm.localStatChangedPos.Clear (); vm.markingLocalChangePos = false; m = vm.labelMaping [jmpLabel]; skipNode = true; jumpped = true; } else { if (vm.markingLocalChangePos) { vm.localStatChangedPos.Clear (); vm.markingLocalChangePos = false; } List<int> jumplist = new List<int> (); ILLabel[] lbList = expr.Operand as ILLabel[]; foreach (ILLabel tmp in lbList) { jumplist.Add (vm.labelMaping [tmp]); } jumplist.Add (m + 1); // the default pos; if (!vm.addNewNode(node, m)) return; skipNode = true; foreach (int tmp in jumplist) { ScanLine (vm, tmp, vm.usefulList.Count); } return; } } else if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave) { ILLabel lb = expr.Operand as ILLabel; if (lb == null) { //impossible throw new SymbolicAnalysisFailedException (); } int lbPos = vm.labelMaping [lb]; if (!vm.addNewNode(node, m)) return; if (lbPos < m) ScanLine (vm, lbPos, m); else ScanLine(vm, lbPos, vm.usefulList.Count); return; } else if (isFlowControlCode (expr.Code)) { ILLabel lb = expr.Operand as ILLabel; if (lb == null) { //impossible throw new SymbolicAnalysisFailedException (); } if (expr == vm.firstStatSwitchExpr) { int testvalue = 0; skipNode = true; if ((expr.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (expr.Arguments [0].Operand as FieldReference) == stateField)) { testvalue = vm.fieldStat; } else testvalue = vm.localStat; if (isMatchControlBr (expr.Code, testvalue)) { vm.addNewNode (new ILExpression (ILCode.Br, lb), m); m = vm.labelMaping [lb]; jumpped = true; } else { vm.addNewNode (new ILExpression (ILCode.Nop, null, new List<ILExpression>()), m); Console.WriteLine ("not maching, should skip this and continue"); } if (vm.markingLocalChangePos) { vm.localStatChangedPos.Clear (); vm.markingLocalChangePos = false; } } else { if (vm.markingLocalChangePos) { vm.localStatChangedPos.Clear (); vm.markingLocalChangePos = false; } int lbPos = vm.labelMaping [lb]; if (!vm.addNewNode (node, m)) return; if (lbPos < m) { ScanLine (vm, lbPos, m); ScanLine (vm, m + 1, vm.usefulList.Count); } else { ScanLine (vm, m + 1, lbPos); ScanLine (vm, lbPos, vm.usefulList.Count); } return; } } else if (expr.Code == ILCode.Stloc) { if (expr.Operand == vm.statILVariable) { if (expr.Arguments [0].Code == ILCode.Ldc_I4) { vm.localStat = (int)expr.Arguments [0].Operand; vm.localStatChangedPos [vm.localStat] = m; } else if (expr.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (expr.Arguments [0].Operand as FieldReference) == stateField) { vm.localStat = vm.fieldStat; //mark the local state for use when we process jump vm.localStatChangedPos.Clear (); vm.markingLocalChangePos = true; vm.localStatChangedPos.Add (vm.localStat, m); } else { throw new SymbolicAnalysisFailedException (); } skipNode = true; } else if (expr.Operand == vm.diposeFlagILVariable) { if (expr.Arguments [0].Code != ILCode.Ldc_I4) { throw new SymbolicAnalysisFailedException (); } vm.localDisposeFlag = (int)expr.Arguments [0].Operand; skipNode = true; } else if (expr.Operand == returnVariable) { if (expr.Arguments [0].Code != ILCode.Ldc_I4) { throw new SymbolicAnalysisFailedException (); } vm.localReturnValue = (int)expr.Arguments [0].Operand; skipNode = true; } } else if (expr.Code == ILCode.Stfld) { if (expr.Arguments [0].MatchThis ()) { if (YieldReturnDecompiler.GetFieldDefinition (expr.Operand as FieldReference) == this.stateField) { if (expr.Arguments [1].Code != ILCode.Ldc_I4) { throw new SymbolicAnalysisFailedException (); } vm.fieldStat = (int)expr.Arguments [1].Operand; skipNode = true; } else if (YieldReturnDecompiler.GetFieldDefinition (expr.Operand as FieldReference) == this.currentField) { //state should change vm.addNewNode (new ILExpression (ILCode.YieldReturn, null, expr.Arguments [1]), m); if (m + 1 < vm.usefulList.Count) { ILExpression nextExpr = vm.usefulList [m + 1] as ILExpression; if ( nextExpr.Code == ILCode.Stfld && YieldReturnDecompiler.GetFieldDefinition (nextExpr.Operand as FieldReference) == this.stateField) { vm.fieldStat = (int)nextExpr.Arguments [1].Operand; vm.fieldStatChangedPos [vm.fieldStat] = m + 1; } else { throw new SymbolicAnalysisFailedException (); } } else { throw new SymbolicAnalysisFailedException (); } skipNode = true; return; } } } else if (expr.Code == ILCode.Ret) { if (expr.Arguments [0].Code == ILCode.Ldloc && expr.Arguments [0].Operand == returnVariable) { if (vm.localReturnValue == 0) { skipNode = true; vm.addNewNode (new ILExpression (ILCode.YieldBreak, null), m); } else { //todo nothing. skipNode = true; vm.addNewNode (new ILExpression (ILCode.Ret, null, new List<ILExpression> ()), m); } } else if (expr.Arguments [0].Code == ILCode.Ldc_I4) { int retval = (int)expr.Arguments [0].Operand; if (retval == 0) { skipNode = true; vm.addNewNode (new ILExpression (ILCode.YieldBreak, null), m); } else { //todo nothing. skipNode = true; vm.addNewNode (new ILExpression (ILCode.Ret, null, new List<ILExpression> ()), m); } } else { throw new SymbolicAnalysisFailedException (); } } } if (!skipNode) { if(!vm.addNewNode(node,m)) { return; } } if (!jumpped) { m++; } } }
void AnalyzeMoveNext2() { ILBlock ilMethod = CreateILAst(moveNextMethod); ILExpression lastReturnArg; if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg)) throw new SymbolicAnalysisFailedException(); if (ilMethod.Body.Count == 6 || ilMethod.Body.Count == 5) { Console.WriteLine ("Debug Pos" + ilMethod.ToString ()); } // ILVariable stateVar=null; // ILVariable diposeFlagVar=null; ILLabel lastLabel = null; //can once to retrive pc , current , pc's local, usage ILNode YieldVMStat vm = new YieldVMStat(); for (int i = 0; i < ilMethod.Body.Count; i++) { ILNode node = ilMethod.Body [i]; if (node is ILExpression) { ILExpression expr = node as ILExpression; switch (expr.Code) { case ILCode.Stloc: //if arments is stateField; //set statelocal = local; if (vm.statILVariable == null && expr.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (expr.Arguments [0].Operand as FieldReference) == stateField) { vm.statILVariable = expr.Operand as ILVariable; } break; case ILCode.Ret: //find out the return Jump Lable and stat ILExpression retArg = expr.Arguments [0] as ILExpression; if (retArg.Code == ILCode.Ldloc) { // a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks) returnVariable = (ILVariable)lastReturnArg.Operand; returnLabel = ilMethod.Body.ElementAtOrDefault (ilMethod.Body.Count - 2) as ILLabel; if (returnLabel == null) throw new SymbolicAnalysisFailedException (); } else { // b) the compiler directly returns constants if (retArg.Code != ILCode.Ldc_I4) { throw new SymbolicAnalysisFailedException (); } if ((int)retArg.Operand == 0) { returnFalseLabel = lastLabel; } else { returnTrueLabel = lastLabel; } } break; } vm.usefulList.Add (expr); } else if (node is ILTryCatchBlock) { ILTryCatchBlock tryBlock = node as ILTryCatchBlock; //check if a state try //finally block is not null, contains dispose , fault block is null, catch block.count==0 //exand it to usageList bool isStateTry = false; if (tryBlock.FaultBlock == null && tryBlock.CatchBlocks.Count == 0 && tryBlock.FinallyBlock != null) { foreach (var tn in tryBlock.FinallyBlock.Body) { if (tn is ILExpression && (tn as ILExpression).Code ==ILCode.Callvirt ) { ILExpression tnexp = (tn as ILExpression); if ( (tnexp.Operand as MethodReference).Name=="Dispose" && tnexp.Arguments.Count==1 && tnexp.Arguments [0] is ILExpression ) { ILExpression disposeArg = tnexp.Arguments [0]; if (disposeArg.Arguments.Count==1 && disposeArg.Arguments [0].MatchThis ()) { isStateTry = true; } } } } } if (isStateTry) { foreach (ILNode blkNode in tryBlock.TryBlock.Body) { vm.usefulList.Add (blkNode); } foreach (ILNode blkNode in tryBlock.FinallyBlock.Body) { if (blkNode is ILExpression) { ILExpression blkExpr = blkNode as ILExpression; if (blkExpr.Code == ILCode.Stloc && vm.diposeFlagILVariable == null && blkExpr.Operand != vm.statILVariable && blkExpr.Arguments [0].Code == ILCode.Ldc_I4) { vm.diposeFlagILVariable = blkExpr.Operand as ILVariable; } } } } else { if (tryBlock.TryBlock != null) { foreach (ILNode blkNode in tryBlock.TryBlock.Body) { vm.usefulList.Add (blkNode); vm.tryBlockMapping [vm.usefulList.Count - 1] = new ILTryCatchBlockInfo(){blk=tryBlock,nodelistRef=tryBlock.TryBlock.Body}; } tryBlock.TryBlock.Body.Clear (); } if (tryBlock.FinallyBlock != null) { foreach (ILNode blkNode in tryBlock.FinallyBlock.Body) { vm.usefulList.Add (blkNode); vm.tryBlockMapping [vm.usefulList.Count - 1] = new ILTryCatchBlockInfo(){blk=tryBlock,nodelistRef=tryBlock.FinallyBlock.Body}; } tryBlock.FinallyBlock.Body.Clear (); } if (tryBlock.CatchBlocks.Count != 0) { foreach (ILTryCatchBlock.CatchBlock blk in tryBlock.CatchBlocks) { foreach (ILNode blkNode in blk.Body) { vm.usefulList.Add (blkNode); vm.tryBlockMapping [vm.usefulList.Count - 1] = new ILTryCatchBlockInfo () { blk = tryBlock, nodelistRef = blk.Body }; } blk.Body.Clear (); } } if (tryBlock.FaultBlock != null) { foreach (ILNode blkNode in tryBlock.FaultBlock.Body) { vm.usefulList.Add (blkNode); vm.tryBlockMapping [vm.usefulList.Count - 1] = new ILTryCatchBlockInfo(){blk=tryBlock,nodelistRef=tryBlock.FaultBlock.Body}; } tryBlock.FaultBlock.Body.Clear (); } } } else if (node is ILLabel) { lastLabel = node as ILLabel; vm.usefulList.Add (node); } else { //add it to usageList vm.usefulList.Add (node); } } //make all the lable and get first case swith // bool expectedSwitchFollowBr = false; for (int i = 0; i < vm.usefulList.Count; i++) { ILNode node = vm.usefulList [i]; if (node is ILExpression) { ILExpression expr = node as ILExpression; if (expr.Code == ILCode.Switch && vm.firstStatSwitchExpr == null && expr.Arguments.Count == 1) { if ((expr.Arguments [0].Code == ILCode.Ldloc && expr.Arguments [0].Operand == vm.statILVariable) || (expr.Arguments [0].Code == ILCode.Ldfld && GetFieldDefinition (expr.Arguments [0].Operand as FieldReference) == stateField)) { foreach (ILLabel lb in (expr.Operand as ILLabel[])) { vm.fistStateSwitchLabelList.Add (lb); } vm.firstStatSwitchExpr = expr; expectedSwitchFollowBr = true; } } else if (isFlowControlCode (expr.Code) && expr.Arguments.Count>0 && expr.Arguments[0].Operand==vm.statILVariable) { ILLabel lb = expr.Operand as ILLabel; vm.fistStateSwitchLabelList.Add (lb); vm.firstStatSwitchExpr = expr; } else if (expr.Code == ILCode.Br && expectedSwitchFollowBr) { expectedSwitchFollowBr = false; if (initPCValue < 0) { vm.fistStateSwitchLabelList.Insert (0, expr.Operand as ILLabel); } else { vm.fistStateSwitchLabelList.Add (expr.Operand as ILLabel); } } } else if (node is ILTryCatchBlock) { } else if (node is ILLabel) { vm.labelMaping [(node as ILLabel)] = i; } } int scanTimes = vm.fistStateSwitchLabelList.Count; if (initPCValue == 0) scanTimes -= 1; //scan all first swith stat // for(int i=0; i<scanTimes;i++) { vm.resetStatVariable (); if(initPCValue==0 ) { vm.fieldStat=i; } else { if(i==0) { vm.fieldStat=initPCValue; } else { vm.fieldStat =i-1; } } vm.scanningStat = vm.fieldStat; ScanLine (vm,0,vm.usefulList.Count); if(vm.fieldStatChangedPos.Count==0 && i==0 && i<scanTimes && initPCValue<0) { Console.WriteLine("A compiler bug? .fieldStatChangedPos.Count==0 && i==0 && i<scanTimes && initPCValue<0 at method: " + moveNextMethod.FullName + "\n:" + vm.outputNewBody()); vm.clearCreatedNodes(); } } // vm.fieldStat=initPCValue; // ScanLine (vm, 0); createdBody = vm.outputNewBody (); if (ilMethod.Body.Count == 6 || ilMethod.Body.Count == 5) { Console.WriteLine ("xxxx size " + createdBody.Count); } Console.WriteLine ("create size " + createdBody.Count); }