/// <summary> /// Visits the TryBlock. /// /// Returns a new State object representing the exceptional control flow transfer out of the try block. /// </summary> protected State HandleTryBlock(TryInstruction inst) { State oldStateOnException = currentStateOnException; State newStateOnException; if (stateOnException.TryGetValue(inst, out newStateOnException)) { newStateOnException.JoinWith(state); } else { newStateOnException = state.Clone(); stateOnException.Add(inst, newStateOnException); } currentStateOnException = newStateOnException; inst.TryBlock.AcceptVisitor(this); // swap back to the old object instance currentStateOnException = oldStateOnException; // No matter what kind of try-instruction this is, it's possible // that an async exception is thrown immediately in the handler block, // so propagate the state: oldStateOnException.JoinWith(newStateOnException); return(newStateOnException); }
public virtual void Visit(TryInstruction instruction) { }
private string TryReduceTry(BasicBlock root, TryBasicBlock trybb) { var group = new Set<BasicBlock> { trybb }; var leavetrybb = trybb.Body as LeaveTryBasicBlock; if (leavetrybb == null || leavetrybb.HandlerPopCount != 1) return null; group.Add(leavetrybb); var handlers = new Seq<TryInstructionHandler>(); foreach (var tbbHandler in trybb.Handlers) { var catchh = tbbHandler as TBBCatchHandler; if (catchh != null) { if (!(catchh.Body is NonReturningBasicBlock)) { // If body is not already free of control flow, check if it can be made to fall // through to after try var leavecatchbb = catchh.Body as LeaveCatchBasicBlock; if (leavecatchbb == null || leavecatchbb.HandlerPopCount != 1 || !leavecatchbb.Target.Equals(leavetrybb.Target)) return null; if (!group.Add(leavecatchbb)) // Should never happen return null; } // else: catch ends with a return, throw, rethrow, break or continue // Catch body WILL NOT end with leave handlers.Add(new CatchTryInstructionHandler(catchh.Type, catchh.Body.Block)); } else { var faulth = tbbHandler as TBBFaultHandler; if (faulth != null) { // Body must be an end fault var endfaultbb = faulth.Body as EndFaultBasicBlock; if (endfaultbb == null) return null; if (!group.Add(endfaultbb)) // Should never happen return null; // Fault handler body WILL NOT end with endfinally/endfault handlers.Add(new FaultTryInstructionHandler(endfaultbb.Block)); } else { var finallyh = tbbHandler as TBBFinallyHandler; if (finallyh != null) { // Body must be an end finally var endfinallybb = finallyh.Body as EndFinallyBasicBlock; if (endfinallybb == null) return null; if (!group.Add(endfinallybb)) // Should never happen return null; // Finally handler body WILL NOT end with endfinally/endfault handlers.Add(new FinallyTryInstructionHandler(endfinallybb.Block)); } else throw new InvalidOperationException("unrecognized handler"); } } } // Try body WILL NOT end with leave var tryi = new TryInstruction(NextInstructionId--, leavetrybb.Block, handlers) { BeforeState = trybb.Block.BeforeState, AfterState = leavetrybb.Block.AfterState }; var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(tryi), leavetrybb.Target); root.Coalesce(trybb, group, newbb); return String.Format("structural try/catch/finally/fault from B{0}", trybb.Id); }
public virtual void Visit(TryInstruction instruction) { Default(instruction); }