private IEnumerable <JSStatement> CreateJsFaultBlock(FaultBlock faultBlock, int p) { var block = CreateJsBlock(faultBlock, p); block.Statements.Add(JSFactory.Statement(new JSThrowExpression { Expression = new JSIdentifier { Name = "__error__" } })); yield return(new JSIfStatement { Condition = new JSBinaryExpression { Left = new JSIdentifier { Name = "__error_handled_" + (block.Depth - 1) + "__" }, Operator = "===", Right = new JSBoolLiteral { Value = false } }, Statements = block.Build().ToList() }); }
public void Preprocess(ILConversion conversion, ConvertedRoutine routine) { if (routine.IsExceptionHandlingInfoPreprocessed) { return; } routine.IsExceptionHandlingInfoPreprocessed = true; routine.ExceptionHandlingInfo = new ExceptionHandlingInfo(); var handlingInfo = routine.ExceptionHandlingInfo; var methodDefinition = (MethodDefinition)routine.MethodReference; var methodDefinitionBody = methodDefinition.Body; if (!methodDefinitionBody.HasExceptionHandlers) { return; } foreach (var exceptionBlock in methodDefinitionBody.ExceptionHandlers) { switch (exceptionBlock.HandlerType) { case ExceptionHandlerType.Filter: { var filterBlock = new FilterBlock() { TryStartOffset = exceptionBlock.TryStart.Offset, TryEndOffset = exceptionBlock.TryEnd.Offset, HandlerEndOffset = exceptionBlock.HandlerEnd.Offset, FilterStartOffset = exceptionBlock.FilterStart?.Offset ?? -1, ExceptionHandler = exceptionBlock }; handlingInfo.ExceptionBlocks.Add(filterBlock); AddEvent(conversion, ExceptionBlockEventKind.Begin, handlingInfo, exceptionBlock.TryStart.Offset, filterBlock); AddEvent(conversion, ExceptionBlockEventKind.Finally, handlingInfo, exceptionBlock.HandlerStart.Offset, filterBlock); AddEvent(conversion, ExceptionBlockEventKind.EndBlock, handlingInfo, exceptionBlock.HandlerEnd.Offset, filterBlock); break; } case ExceptionHandlerType.Fault: { var faultBlock = new FaultBlock() { TryStartOffset = exceptionBlock.TryStart.Offset, TryEndOffset = exceptionBlock.TryEnd.Offset, HandlerEndOffset = exceptionBlock.HandlerEnd.Offset, FilterStartOffset = exceptionBlock.FilterStart?.Offset ?? -1, ExceptionHandler = exceptionBlock }; handlingInfo.ExceptionBlocks.Add(faultBlock); AddEvent(conversion, ExceptionBlockEventKind.Begin, handlingInfo, exceptionBlock.TryStart.Offset, faultBlock); AddEvent(conversion, ExceptionBlockEventKind.Finally, handlingInfo, exceptionBlock.HandlerStart.Offset, faultBlock); AddEvent(conversion, ExceptionBlockEventKind.EndBlock, handlingInfo, exceptionBlock.HandlerEnd.Offset, faultBlock); break; } case ExceptionHandlerType.Finally: { var finallyBlock = new TryFinallyBlock() { TryStartOffset = exceptionBlock.TryStart.Offset, TryEndOffset = exceptionBlock.TryEnd.Offset, HandlerEndOffset = exceptionBlock.HandlerEnd.Offset, FilterStartOffset = exceptionBlock.FilterStart?.Offset ?? -1, ExceptionHandler = exceptionBlock }; handlingInfo.ExceptionBlocks.Add(finallyBlock); AddEvent(conversion, ExceptionBlockEventKind.Begin, handlingInfo, exceptionBlock.TryStart.Offset, finallyBlock); AddEvent(conversion, ExceptionBlockEventKind.Finally, handlingInfo, exceptionBlock.HandlerStart.Offset, finallyBlock); AddEvent(conversion, ExceptionBlockEventKind.EndBlock, handlingInfo, exceptionBlock.HandlerEnd.Offset, finallyBlock); break; } case ExceptionHandlerType.Catch: { TryCatchBlock tryCatchBlock = null; for (int i = 0; i < handlingInfo.TryCatchEntries.Count; i++) { var x = handlingInfo.TryCatchEntries[i]; if (x.TryStartOffset == exceptionBlock.TryStart.Offset && x.TryEndOffset == exceptionBlock.TryEnd.Offset) { tryCatchBlock = x; } } if (tryCatchBlock == null) { tryCatchBlock = new TryCatchBlock() { // The first instruction that is included in the try catch block TryStartOffset = exceptionBlock.TryStart.Offset, // Gets the first instruction of the catch statement TryEndOffset = exceptionBlock.TryEnd.Offset, // Gets the first instruction that is outside of the catch statement HandlerEndOffset = exceptionBlock.HandlerEnd.Offset, FilterStartOffset = exceptionBlock.FilterStart?.Offset ?? -1, HandlerEntries = new Dictionary <int, List <ExceptionHandler> >() }; handlingInfo.TryCatchEntries.Add(tryCatchBlock); handlingInfo.ExceptionBlocks.Add(tryCatchBlock); System.Diagnostics.Debug.WriteLine($"Try-Catch: BEGIN @ {exceptionBlock.TryStart.Offset.ToString("X2")}"); AddEvent(conversion, ExceptionBlockEventKind.Begin, handlingInfo, exceptionBlock.TryStart.Offset, tryCatchBlock); } if (!tryCatchBlock.HandlerEntries.TryGetValue(exceptionBlock.HandlerStart.Offset, out List <ExceptionHandler> list)) { list = new List <ExceptionHandler>(); tryCatchBlock.HandlerEntries.Add(exceptionBlock.HandlerStart.Offset, list); } list.Add(exceptionBlock); System.Diagnostics.Debug.WriteLine($"Try-Catch: CATCH @ {exceptionBlock.HandlerStart.Offset.ToString("X2")}"); AddEvent(conversion, ExceptionBlockEventKind.Catch, handlingInfo, exceptionBlock.HandlerStart.Offset, tryCatchBlock, exceptionBlock); break; } default: { throw new NotSupportedException(); } } } for (int i = 0; i < handlingInfo.TryCatchEntries.Count; i++) { var tryCatchBlock = handlingInfo.TryCatchEntries[i]; ExceptionHandler lastHandlerEntry = null; var handlerEntriesListList = tryCatchBlock.HandlerEntries.Values.ToList(); for (int j = 0; j < handlerEntriesListList.Count; j++) { var currentHandlerEntryList = handlerEntriesListList[j]; for (int k = 0; k < currentHandlerEntryList.Count; k++) { var currentHandlerEntry = currentHandlerEntryList[k]; if (lastHandlerEntry == null) { lastHandlerEntry = currentHandlerEntry; } else if (currentHandlerEntry.HandlerEnd.Offset > lastHandlerEntry.HandlerEnd.Offset) { lastHandlerEntry = currentHandlerEntry; } } } if (lastHandlerEntry == null) { continue; } System.Diagnostics.Debug.WriteLine($"Try-Catch: END CATCH @ {lastHandlerEntry.HandlerEnd.Offset.ToString("X2")}"); AddEvent(conversion, ExceptionBlockEventKind.EndBlock, handlingInfo, lastHandlerEntry.HandlerEnd.Offset, tryCatchBlock); } }
private IEnumerable <JSStatement> CreateJsCatchBlock(IEnumerable <CatchBlock> catchBlocks, FaultBlock faultBlock, int p) { if (catchBlocks.Count() == 1 && catchBlocks.First().CatchType == null) { yield return(new JSCatchBlock { Error = new JSIdentifier { Name = "_" } }); yield break; } var handledFlag = new JSIdentifier { Name = "__error_handled_" + p + "__" }; var statements = new List <JSStatement> { JSFactory.Statement( new JSVariableDelcaration { Name = handledFlag.Name, Value = new JSBoolLiteral { Value = false } }) }; var exceptionObject = new JSIdentifier { Name = "__error__" }; foreach (var catchBlock in catchBlocks) { var block = CreateJsBlock(catchBlock, p); int index; for (index = 0; index < block.Statements.Count; index++) { var es = block.Statements[index] as JSSwitchCase; if (es == null) { break; } } block.Statements.Insert(index, JSFactory .Assignment(handledFlag, new JSBoolLiteral { Value = true }) .ToStatement()); // assign the exception object to expressions reading from top of the stack // ok this is too delicate.. we happen to know it is the second expression.. var expression = catchBlock.Ast.Skip(1).FirstOrDefault() as OpExpression; if (expression != null) { var locations = expression .StackBefore .First() .Definitions .Cast <ExceptionNode>() .SelectMany(e => e.StoreLocations) ; foreach (var location in locations) { block.Statements.Insert(index, JSFactory.Assignment(location.Name, exceptionObject).ToStatement()); } } statements.Add(new JSIfStatement { Condition = new JSBinaryExpression { Left = new JSUnaryExpression { Operand = handledFlag, Operator = "!" }, Operator = "&&", Right = new JSBinaryExpression { Left = exceptionObject, Operator = "instanceof", Right = GetTypeIdentifier(catchBlock.CatchType, method.ReflectionMethod, type.ReflectionType, this_) } }, Statements = block.Build().ToList() }); } statements.Add(new JSIfStatement { Condition = new JSUnaryExpression { Operand = handledFlag, Operator = "!" }, Statements = { new JSThrowExpression { Expression = exceptionObject }.ToStatement() } }); if (faultBlock != null) { statements.AddRange(CreateJsFaultBlock(faultBlock, p)); } yield return(new JSCatchBlock { Error = exceptionObject, Statements = statements }); }