/// <summary> /// Create try/catch/finally/fault block /// </summary> public override RLRange Visit(AstTryCatchBlock node, AstNode parent) { var handler = new ExceptionHandler(); //if (node.FaultBlock != null) //{ // Debugger.Break(); //} // Setup instruction before/after my node. var first = new Instruction() { SequencePoint = node.SourceLocation }; var last = new Instruction(RCode.Nop); FinallyBlockState finState = null; FinallyBlockState outerFinState = tryCatchStack.FirstOrDefault(f => f.HasFinally); if (tryCatchStack.Count == 0) { finallyState.FinallyStacks.Add(new List <FinallyBlockState>()); } if (node.FinallyBlock != null) { // store finaly state finState = new FinallyBlockState(outerFinState, tryCatchStack.Count, this, first, last); finState.FinallyExceptionRegister = frame.AllocateTemp(new ClassReference("java.lang.Throwable")).Register; // clear the variable to make sure it isn't stale from a previous loop. // make sure this is outside the try block for edge case exceptions. this.Add(node.SourceLocation, RCode.Const, 0, finState.FinallyExceptionRegister); tryCatchStack.Push(finState); finallyState.FinallyStacks.Last().Add(finState); } else { finState = new FinallyBlockState(outerFinState, tryCatchStack.Count); tryCatchStack.Push(finState); } instructions.Add(first); // Emit try block handler.TryStart = first; node.TryBlock.AcceptOrDefault(this, node); handler.TryEnd = TryCatchGotoEnd(finState, last); var catchesStart = this.Add(AstNode.NoSource, RCode.Nop); // Emit "normal" catch blocks foreach (var catchBlock in node.CatchBlocks.Where(x => !x.IsCatchAll())) { var c = new Catch { Type = catchBlock.ExceptionType.GetReference(targetPackage) }; handler.Catches.Add(c); var catchStart = this.Add(catchBlock.SourceLocation, RCode.Nop); catchBlock.Accept(this, node); c.Instruction = catchStart; TryCatchGotoEnd(finState, last); } // Emit "catch all" (if any) var catchAllBlock = node.CatchBlocks.SingleOrDefault(x => x.IsCatchAll()); if (catchAllBlock != null) { var catchStart = this.Add(catchAllBlock.SourceLocation, RCode.Nop); catchAllBlock.Accept(this, node); handler.CatchAll = catchStart; TryCatchGotoEnd(finState, last); } var catchesEnd = this.Add(AstNode.NoSource, RCode.Nop); // clear try/catch/finally stack: we don't want to cover ourselves! tryCatchStack.Pop(); // Emit finally code if (node.FinallyBlock != null) { // preparation. var finallyStart = this.Add(node.FinallyBlock.SourceLocation, RCode.Move_exception, finState.FinallyExceptionRegister); instructions.Add(finState.NonException); // the original handler node.FinallyBlock.Accept(this, node); // prepare the routing this.Add(AstNode.NoSource, RCode.If_eqz, finState.AfterExceptionCheck, finState.FinallyExceptionRegister); this.Add(AstNode.NoSource, RCode.Throw, finState.FinallyExceptionRegister); instructions.Add(finState.AfterExceptionCheck); // Set up exception handlers. if (catchAllBlock == null) { // we need to cover the try block. handler.CatchAll = finallyStart; } if (node.CatchBlocks.Any()) { // we need to cover the catch blocks var finallyHandler = new ExceptionHandler { TryStart = catchesStart, TryEnd = catchesEnd, CatchAll = finallyStart }; body.Exceptions.Add(finallyHandler); } } // Add end instructions.Add(last); // Record catch/catch-all handler if ((handler.CatchAll != null) || handler.Catches.Any()) { body.Exceptions.Add(handler); } return(new RLRange(first, last, null)); }
/// <summary> /// Create try/catch/finally/fault block /// </summary> public override RLRange Visit(AstTryCatchBlock node, AstNode parent) { var handler = new ExceptionHandler(); //if (node.FaultBlock != null) //{ // Debugger.Break(); //} // Setup instruction before/after my node. var first = new Instruction() { SequencePoint = node.SourceLocation}; var last = new Instruction(RCode.Nop); FinallyBlockState finState = null; FinallyBlockState outerFinState = tryCatchStack.FirstOrDefault(f => f.HasFinally); if (tryCatchStack.Count == 0) finallyState.FinallyStacks.Add(new List<FinallyBlockState>()); if (node.FinallyBlock != null) { // store finaly state finState = new FinallyBlockState(outerFinState, tryCatchStack.Count, this, first, last); finState.FinallyExceptionRegister = frame.AllocateTemp(new ClassReference("java.lang.Throwable")).Register; // clear the variable to make sure it isn't stale from a previous loop. // make sure this is outside the try block for edge case exceptions. this.Add(node.SourceLocation, RCode.Const, 0, finState.FinallyExceptionRegister); tryCatchStack.Push(finState); finallyState.FinallyStacks.Last().Add(finState); } else { finState = new FinallyBlockState(outerFinState, tryCatchStack.Count); tryCatchStack.Push(finState); } instructions.Add(first); // Emit try block handler.TryStart = first; node.TryBlock.AcceptOrDefault(this, node); handler.TryEnd = TryCatchGotoEnd(finState, last); var catchesStart = this.Add(AstNode.NoSource, RCode.Nop); // Emit "normal" catch blocks foreach (var catchBlock in node.CatchBlocks.Where(x => !x.IsCatchAll())) { var c = new Catch { Type = catchBlock.ExceptionType.GetReference(targetPackage) }; handler.Catches.Add(c); var catchStart = this.Add(catchBlock.SourceLocation, RCode.Nop); catchBlock.Accept(this, node); c.Instruction = catchStart; TryCatchGotoEnd(finState, last); } // Emit "catch all" (if any) var catchAllBlock = node.CatchBlocks.SingleOrDefault(x => x.IsCatchAll()); if (catchAllBlock != null) { var catchStart = this.Add(catchAllBlock.SourceLocation, RCode.Nop); catchAllBlock.Accept(this, node); handler.CatchAll = catchStart; TryCatchGotoEnd(finState, last); } var catchesEnd = this.Add(AstNode.NoSource, RCode.Nop); // clear try/catch/finally stack: we don't want to cover ourselves! tryCatchStack.Pop(); // Emit finally code if (node.FinallyBlock != null) { // preparation. var finallyStart = this.Add(node.FinallyBlock.SourceLocation, RCode.Move_exception, finState.FinallyExceptionRegister); instructions.Add(finState.NonException); // the original handler node.FinallyBlock.Accept(this, node); // prepare the routing this.Add(AstNode.NoSource, RCode.If_eqz, finState.AfterExceptionCheck, finState.FinallyExceptionRegister); this.Add(AstNode.NoSource, RCode.Throw, finState.FinallyExceptionRegister); instructions.Add(finState.AfterExceptionCheck); // Set up exception handlers. if (catchAllBlock == null) { // we need to cover the try block. handler.CatchAll = finallyStart; } if (node.CatchBlocks.Any()) { // we need to cover the catch blocks var finallyHandler = new ExceptionHandler { TryStart = catchesStart, TryEnd = catchesEnd, CatchAll = finallyStart }; body.Exceptions.Add(finallyHandler); } } // Add end instructions.Add(last); // Record catch/catch-all handler if ((handler.CatchAll != null) || handler.Catches.Any()) { body.Exceptions.Add(handler); } return new RLRange(first, last, null); }