예제 #1
0
        public JSTryCatchBlock TranslateNode(ILTryCatchBlock tcb)
        {
            var body = TranslateNode(tcb.TryBlock);
            JSVariable catchVariable = null;
            JSBlockStatement catchBlock = null;
            JSBlockStatement finallyBlock = null;

            if (tcb.CatchBlocks.Count > 0) {
                var pairs = new List<KeyValuePair<JSExpression, JSStatement>>();
                catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference));

                bool foundUniversalCatch = false;
                foreach (var cb in tcb.CatchBlocks) {
                    JSExpression pairCondition = null;

                    if (
                        (cb.ExceptionType.FullName == "System.Exception") ||
                        (cb.ExceptionType.FullName == "System.Object")
                    ) {
                        // Bad IL sometimes contains entirely meaningless catch clauses. It's best to just ignore them.
                        if (
                            (cb.Body.Count == 1) && (cb.Body[0] is ILExpression) &&
                            (((ILExpression)cb.Body[0]).Code == ILCode.Rethrow)
                        ) {
                            continue;
                        }

                        if (foundUniversalCatch) {
                            Console.Error.WriteLine("Found multiple catch-all catch clauses. Any after the first will be ignored.");
                            continue;
                        }

                        foundUniversalCatch = true;
                    } else {
                        if (foundUniversalCatch)
                            throw new NotImplementedException("Catch-all clause must be last");

                        pairCondition = JSIL.CheckType(catchVariable, cb.ExceptionType);
                    }

                    var pairBody = TranslateBlock(cb.Body);

                    if (cb.ExceptionVariable != null) {
                        var excVariable = DeclareVariable(cb.ExceptionVariable, ThisMethodReference);

                        pairBody.Statements.Insert(
                            0, new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                JSOperator.Assignment, excVariable,
                                catchVariable, cb.ExceptionVariable.Type
                            ))
                        );
                    }

                    pairs.Add(new KeyValuePair<JSExpression, JSStatement>(
                        pairCondition, pairBody
                    ));
                }

                if (!foundUniversalCatch)
                    pairs.Add(new KeyValuePair<JSExpression,JSStatement>(
                        null, new JSExpressionStatement(new JSThrowExpression(catchVariable))
                    ));

                if ((pairs.Count == 1) && (pairs[0].Key == null))
                    catchBlock = new JSBlockStatement(
                        pairs[0].Value
                    );
                else
                    catchBlock = new JSBlockStatement(
                        JSIfStatement.New(pairs.ToArray())
                    );
            }

            if (tcb.FinallyBlock != null)
                finallyBlock = TranslateNode(tcb.FinallyBlock);

            if (tcb.FaultBlock != null) {
                if (catchBlock != null)
                    throw new Exception("A try block cannot have both a catch block and a fault block");

                catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference));
                catchBlock = new JSBlockStatement(TranslateBlock(tcb.FaultBlock.Body));

                catchBlock.Statements.Add(new JSExpressionStatement(new JSThrowExpression(catchVariable)));
            }

            return new JSTryCatchBlock(
                body, catchVariable, catchBlock, finallyBlock
            );
        }
예제 #2
0
        void ValidateCatchBlock(ILTryCatchBlock.CatchBlock catchBlock)
        {
            if (catchBlock.ExceptionType == null || catchBlock.ExceptionType.TypeName != "Exception")
                throw new SymbolicAnalysisFailedException();
            if (catchBlock.Body.Count != 3)
                throw new SymbolicAnalysisFailedException();
            int stateID;
            if (!(MatchStateAssignment(catchBlock.Body[0], out stateID) && stateID == finalState))
                throw new SymbolicAnalysisFailedException();
            IMethod setExceptionMethod;
            ILExpression builderExpr, exceptionExpr;
            if (!catchBlock.Body[1].Match(ILCode.Call, out setExceptionMethod, out builderExpr, out exceptionExpr))
                throw new SymbolicAnalysisFailedException();
            if (!(setExceptionMethod.Name == "SetException" && IsBuilderFieldOnThis(builderExpr) && exceptionExpr.MatchLdloc(catchBlock.ExceptionVariable)))
                throw new SymbolicAnalysisFailedException();

            ILLabel label;
            if (!(catchBlock.Body[2].Match(ILCode.Leave, out label) && label == exitLabel))
                throw new SymbolicAnalysisFailedException();
        }
예제 #3
0
		void ConvertBody(List<ILNode> body, int startPos, int bodyLength, List<KeyValuePair<ILLabel, StateRange>> labels)
		{
			newBody = new List<ILNode>();
			newBody.Add(MakeGoTo(labels, 0));
			List<SetState> stateChanges = new List<SetState>();
			int currentState = -1;
			// Copy all instructions from the old body to newBody.
			for (int pos = startPos; pos < bodyLength; pos++) {
				ILExpression expr = body[pos] as ILExpression;
				if (expr != null && expr.Code == ILCode.Stfld && expr.Arguments[0].MatchThis()) {
					// Handle stores to 'state' or 'current'
					if (GetFieldDefinition(expr.Operand as FieldReference) == stateField) {
						if (expr.Arguments[1].Code != ILCode.Ldc_I4)
							throw new SymbolicAnalysisFailedException();
						currentState = (int)expr.Arguments[1].Operand;
						stateChanges.Add(new SetState(newBody.Count, currentState));
					} else if (GetFieldDefinition(expr.Operand as FieldReference) == currentField) {
						newBody.Add(new ILExpression(ILCode.YieldReturn, null, expr.Arguments[1]));
					} else {
						newBody.Add(body[pos]);
					}
				} else if (returnVariable != null && expr != null && expr.Code == ILCode.Stloc && expr.Operand == returnVariable) {
					// handle store+branch to the returnVariable
					ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
					if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnLabel || expr.Arguments[0].Code != ILCode.Ldc_I4)
						throw new SymbolicAnalysisFailedException();
					int val = (int)expr.Arguments[0].Operand;
					if (val == 0) {
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (val == 1) {
						newBody.Add(MakeGoTo(labels, currentState));
					} else {
						throw new SymbolicAnalysisFailedException();
					}
				} else if (expr != null && expr.Code == ILCode.Ret) {
					if (expr.Arguments.Count != 1 || expr.Arguments[0].Code != ILCode.Ldc_I4)
						throw new SymbolicAnalysisFailedException();
					// handle direct return (e.g. in release builds)
					int val = (int)expr.Arguments[0].Operand;
					if (val == 0) {
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (val == 1) {
						newBody.Add(MakeGoTo(labels, currentState));
					} else {
						throw new SymbolicAnalysisFailedException();
					}
				} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis()) {
					MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
					if (method == null)
						throw new SymbolicAnalysisFailedException();
					StateRange stateRange;
					if (method == disposeMethod) {
						// Explicit call to dispose is used for "yield break;" within the method.
						ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
						if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
							throw new SymbolicAnalysisFailedException();
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) {
						// Call to Finally-method
						int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState));
						if (index < 0)
							throw new SymbolicAnalysisFailedException();
						
						ILLabel label = new ILLabel();
						label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState;
						newBody.Add(new ILExpression(ILCode.Leave, label));
						
						SetState stateChange = stateChanges[index];
						// Move all instructions from stateChange.Pos to newBody.Count into a try-block
						stateChanges.RemoveRange(index, stateChanges.Count - index); // remove all state changes up to the one we found
						ILTryCatchBlock tryFinally = new ILTryCatchBlock();
						tryFinally.TryBlock = new ILBlock(newBody.GetRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos));
						newBody.RemoveRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos); // remove all nodes that we just moved into the try block
						tryFinally.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>();
						tryFinally.FinallyBlock = ConvertFinallyBlock(method);
						newBody.Add(tryFinally);
						newBody.Add(label);
					}
				} else {
					newBody.Add(body[pos]);
				}
			}
			newBody.Add(new ILExpression(ILCode.YieldBreak, null));
		}
예제 #4
0
        List<ILNode> ConvertBody(List<ILNode> body, int startPos, int bodyLength, LabelRangeMapping mapping)
        {
            List<ILNode> newBody = new List<ILNode>();
            // Copy all instructions from the old body to newBody.
            for (int pos = startPos; pos < bodyLength; pos++) {
                ILTryCatchBlock tryCatchBlock = body[pos] as ILTryCatchBlock;
                ILExpression expr = body[pos] as ILExpression;
                if (expr != null && expr.Code == ILCode.Leave && expr.Operand == exitLabel) {
                    ILVariable awaiterVar;
                    FieldDef awaiterField;
                    int targetStateID;
                    HandleAwait(newBody, out awaiterVar, out awaiterField, out targetStateID);
                    MarkAsGeneratedVariable(awaiterVar);
                    newBody.Add(new ILExpression(ILCode.Await, null, new ILExpression(ILCode.Ldloca, awaiterVar)));
                    newBody.Add(MakeGoTo(mapping, targetStateID));
                } else if (tryCatchBlock != null) {
                    ILTryCatchBlock newTryCatchBlock = new ILTryCatchBlock();
                    var tryBody = tryCatchBlock.TryBlock.Body;
                    if (tryBody.Count == 0)
                        throw new SymbolicAnalysisFailedException();
                    StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(tryBody[0], StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar);
                    int tryBodyLength = tryBody.Count;
                    int posInTryBody = rangeAnalysis.AssignStateRanges(tryBody, tryBodyLength);
                    rangeAnalysis.EnsureLabelAtPos(tryBody, ref posInTryBody, ref tryBodyLength);

                    var mappingInTryBlock = rangeAnalysis.CreateLabelRangeMapping(tryBody, posInTryBody, tryBodyLength);
                    var newTryBody = ConvertBody(tryBody, posInTryBody, tryBodyLength, mappingInTryBlock);
                    newTryBody.Insert(0, MakeGoTo(mappingInTryBlock, initialState));

                    // If there's a label at the beginning of the state dispatcher, copy that
                    if (posInTryBody > 0 && tryBody.FirstOrDefault() is ILLabel)
                        newTryBody.Insert(0, tryBody.First());

                    newTryCatchBlock.TryBlock = new ILBlock(newTryBody);
                    newTryCatchBlock.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>(tryCatchBlock.CatchBlocks);
                    newTryCatchBlock.FaultBlock = tryCatchBlock.FaultBlock;
                    if (tryCatchBlock.FinallyBlock != null)
                        newTryCatchBlock.FinallyBlock = new ILBlock(ConvertFinally(tryCatchBlock.FinallyBlock.Body));

                    newBody.Add(newTryCatchBlock);
                } else {
                    newBody.Add(body[pos]);
                }
            }
            return newBody;
        }
예제 #5
0
        void AnalyzeMoveNext()
        {
            ILBlock ilMethod = CreateILAst(moveNextMethod);

            int startIndex;
            if (ilMethod.Body.Count == 6) {
                startIndex = 0;
            } else if (ilMethod.Body.Count == 7) {
                // stloc(cachedState, ldfld(valuetype StateMachineStruct::<>1__state, ldloc(this)))
                ILExpression cachedStateInit;
                if (!ilMethod.Body[0].Match(ILCode.Stloc, out cachedStateVar, out cachedStateInit))
                    throw new SymbolicAnalysisFailedException();
                ILExpression instanceExpr;
                IField loadedField;
                if (!cachedStateInit.Match(ILCode.Ldfld, out loadedField, out instanceExpr) || loadedField.ResolveFieldWithinSameModule() != stateField || !instanceExpr.MatchThis())
                    throw new SymbolicAnalysisFailedException();
                startIndex = 1;
            } else {
                throw new SymbolicAnalysisFailedException();
            }

            mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock;
            if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
                throw new SymbolicAnalysisFailedException();
            if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
                throw new SymbolicAnalysisFailedException();

            setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel;
            if (setResultAndExitLabel == null)
                throw new SymbolicAnalysisFailedException();

            if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState))
                throw new SymbolicAnalysisFailedException();

            // call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
            IMethod setResultMethod;
            ILExpression builderExpr;
            if (methodType == AsyncMethodType.TaskOfT) {
                if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
                    throw new SymbolicAnalysisFailedException();
            } else {
                if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr))
                    throw new SymbolicAnalysisFailedException();
            }
            if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
                throw new SymbolicAnalysisFailedException();

            exitLabel = ilMethod.Body[startIndex + 4] as ILLabel;
            if (exitLabel == null)
                throw new SymbolicAnalysisFailedException();
        }
예제 #6
0
		void AnalyzeMoveNext()
		{
			ILBlock ilMethod = CreateILAst(moveNextMethod);
			
			if (ilMethod.Body.Count != 6)
				throw new SymbolicAnalysisFailedException();
			
			mainTryCatch = ilMethod.Body[0] as ILTryCatchBlock;
			if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
				throw new SymbolicAnalysisFailedException();
			if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
				throw new SymbolicAnalysisFailedException();
			
			setResultAndExitLabel = ilMethod.Body[1] as ILLabel;
			if (setResultAndExitLabel == null)
				throw new SymbolicAnalysisFailedException();
			
			if (!MatchStateAssignment(ilMethod.Body[2], out finalState))
				throw new SymbolicAnalysisFailedException();
			
			// call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
			MethodReference setResultMethod;
			ILExpression builderExpr;
			if (methodType == AsyncMethodType.TaskOfT) {
				if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
					throw new SymbolicAnalysisFailedException();
			} else {
				if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr))
					throw new SymbolicAnalysisFailedException();
			}
			if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
				throw new SymbolicAnalysisFailedException();
			
			exitLabel = ilMethod.Body[4] as ILLabel;
			if (exitLabel == null)
				throw new SymbolicAnalysisFailedException();
		}
예제 #7
0
파일: Nodes.cs 프로젝트: almazik/ILSpy
        public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch)
        {
            TryCatchNode tryCatch = new TryCatchNode();

            Block tryBlock = new Block();
            tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock));
            tryBlock.MoveTo(tryCatch);

            Block finallyBlock = new Block();
            if (ilTryCatch.FinallyBlock != null) {
                finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock));
            }
            finallyBlock.MoveTo(tryCatch);

            foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) {
                tryCatch.Types.Add(cb.ExceptionType);
                Block catchBlock = new Block();
                catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body));
                catchBlock.MoveTo(tryCatch);
            }

            return tryCatch;
        }
예제 #8
0
 protected virtual ILTryCatchBlock VisitTryCatchBlock(ILTryCatchBlock tryCatchBlock)
 {
     foreach (var child in tryCatchBlock.GetChildren())
         Visit(child);
     return tryCatchBlock;
 }