public override Statement VisitThrow(Throw Throw) { WriteLine("raise {0};", ((Identifier)Throw.Expression).Name); return Throw; }
private static Statement WrapTryCatch(Method method, Statement statement) { Block afterCatches = new Block(new StatementList()); Block tryBlock = new Block(new StatementList()); Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(statement); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); tryBlock.Statements.Add(blockAfterTryBody); Block catchBlock = new Block(new StatementList()); // emit code that pops the exception and fools fxcop Block branchTargetToFoolFxCop = new Block(null); var branch = new Branch(new Expression(NodeType.Pop), branchTargetToFoolFxCop); SourceContext hiddenContext = new SourceContext(HiddenDocument.Document); branch.SourceContext = hiddenContext; catchBlock.Statements.Add(branch); var rethrowStatement = new Throw(); rethrowStatement.SourceContext = hiddenContext; rethrowStatement.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(rethrowStatement); catchBlock.Statements.Add(branchTargetToFoolFxCop); var leave = new Branch(null, afterCatches, false, true, true); leave.SourceContext = hiddenContext; catchBlock.Statements.Add(leave); Block tryCatch = new Block(new StatementList()); tryCatch.Statements.Add(tryBlock); tryCatch.Statements.Add(catchBlock); tryCatch.Statements.Add(afterCatches); if (method.ExceptionHandlers == null) method.ExceptionHandlers = new ExceptionHandlerList(); ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = tryBlock; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = afterCatches; exHandler.FilterType = SystemTypes.Exception; exHandler.HandlerType = NodeType.Catch; method.ExceptionHandlers.Add(exHandler); return tryCatch; }
public virtual Statement VisitThrow(Throw Throw) { if (Throw == null) return null; Throw.Expression = this.VisitExpression(Throw.Expression); return Throw; }
//[ContractVerification(true)] private void VisitMethodInternal(Method method) { if (method.IsAbstract || IsRewriterGenerated(method)) { return; } Block origBody = method.Body; if (origBody == null || origBody.Statements == null || origBody.Statements.Count == 0) return; #if DEBUG if (!RewriteHelper.PostNormalizedFormat(method)) throw new RewriteException("The method body for '" + method.FullName + "' is not structured correctly"); #endif #region Rewrite all Assert and Assume methods // Happens in-place so any modifications made are persisted even if nothing else is done to method RewriteAssertAssumeAndCallSiteRequires raa = new RewriteAssertAssumeAndCallSiteRequires(this.AssertAssumeRewriteMethodTable, this.runtimeContracts, this.contractEmitFlags, this, method); method.Body = raa.VisitBlock(method.Body); #endregion Rewrite all Assert and Assume methods (if user specified) #region Bail out early if publicSurfaceOnly and method is not visible (but not for contract validators!) or contract abbreviator if (this.runtimeContracts.PublicSurfaceOnly && !IsCallableFromOutsideAssembly(method) && !ContractNodes.IsValidatorMethod(method) || ContractNodes.IsAbbreviatorMethod(method)) return; #endregion int oldLocalUniqueNameCounter = 0; List<Block> contractInitializationBlocks = new List<Block>(); Block postPreambleBlock = null; Dictionary<TypeNode, Local> closureLocals = new Dictionary<TypeNode, Local>(); Block oldExpressionPreStateValues = new Block(new StatementList()); #region Gather pre- and postconditions from supertypes and from method contract // Create lists of unique preconditions and postconditions. List<Requires> preconditions = new List<Requires>(); List<Ensures> postconditions = new List<Ensures>(); List<Ensures> asyncPostconditions = new List<Ensures>(); RequiresList validations = null; // For postconditions, wrap all parameters within an old expression (if they are not already within one) var wrap = new WrapParametersInOldExpressions(); EmitAsyncClosure asyncBuilder = null; #region Copy the method's contracts. if (method.Contract != null && (method.Contract.RequiresCount > 0 || method.Contract.EnsuresCount > 0 || method.Contract.ValidationsCount > 0 || method.Contract.AsyncEnsuresCount > 0)) { // Use duplicate of contract because it is going to get modified from processing Old(...) and // Result(). Can't have the modified contract get inherited (or else the Old(...) processing // will not work properly.) // Can't use MethodContract.CopyFrom or HelperMethods.DuplicateMethodBodyAndContract // because they assume the new contract is in a different method. Plus the latter duplicates // any closure classes needed for anonymous delegates in the contract. MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, method, this.runtimeContracts.ContractNodes, true); validations = mc.Validations; if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); postPreambleBlock = mc.PostPreamble; RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } #endregion Copy the method's contracts. #region Search the class hierarchy for overridden methods to propagate their contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.OverridesBaseClassMember && method.DeclaringType != null && method.OverriddenMethod != null) { for (TypeNode super = method.DeclaringType.BaseType; super != null; super = HelperMethods.DoesInheritContracts(super)?super.BaseType:null) { var baseMethod = super.GetImplementingMethod(method.OverriddenMethod, false); Method baseContractMethod = HelperMethods.GetContractMethod(baseMethod); if (baseContractMethod != null) { MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, baseContractMethod, this.runtimeContracts.ContractNodes, false); RewriteHelper.ReplacePrivateFieldsThatHavePublicProperties(method.DeclaringType, super, mc, this.rewriterNodes); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in overridden methods, since they cannot be constructors. // only add requires if baseMethod is the root method if (mc.Requires != null && baseMethod.OverriddenMethod == null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } // bail out if this base type does not inherit contracts if (!HelperMethods.DoesInheritContracts(super)) break; } } #endregion Search the class hierarchy for overridden methods to propagate their contracts. #region Propagate explicit interface method contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.ImplementedInterfaceMethods != null) { foreach (Method interfaceMethod in method.ImplementedInterfaceMethods) { if (interfaceMethod != null) { Method contractMethod = HelperMethods.GetContractMethod(interfaceMethod); if (contractMethod != null) { // if null, then no contract for this interface method // Maybe it would be easier to just duplicate the entire method and then pull the // initialization code from the duplicate? MethodContract mc=HelperMethods.DuplicateContractAndClosureParts(method, contractMethod, this.runtimeContracts.ContractNodes, false); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in interface methods (not constructors) if (mc.Requires != null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } } } } #endregion Propagate explicit interface method contracts. #region Propagate implicit interface method contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.ImplicitlyImplementedInterfaceMethods != null) { foreach (Method interfaceMethod in method.ImplicitlyImplementedInterfaceMethods) { if (interfaceMethod != null) { Method contractMethod = HelperMethods.GetContractMethod(interfaceMethod); if (contractMethod != null) { // if null, then no contract for this method // Maybe it would be easier to just duplicate the entire method and then pull the // initialization code from the duplicate? MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, contractMethod, this.runtimeContracts.ContractNodes, false); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in implicit interface method implementations, as they are not constructors. if (mc.Requires != null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } } } } #endregion Propagate implicit interface method contracts. #endregion Gather pre- and postconditions from supertypes and from method contract #region Return if there is nothing to do if (preconditions.Count < 1 && postconditions.Count < 1 && asyncPostconditions.Count < 1 && (validations == null || validations.Count == 0) && this.InvariantMethod == null) return; #endregion Return if there is nothing to do #region Change all short branches to long because code modifications can add code { // REVIEW: This does *not* remove any short branches in the contracts. // I think that is okay, but we should think about it. RemoveShortBranches rsb = new RemoveShortBranches(); rsb.VisitBlock(method.Body); } #endregion Change all short branches to long because code modifications can add code #region Modify method body to change all returns into assignments and branch to unified exit // now modify the method body to change all return statements // into assignments to the local "result" and a branch to a // block at the end that can check the post-condition using // "result" and then finally return it. // [MAF] we do it later once we know if the branches are leaves or just branch. Local result = null; if (!HelperMethods.IsVoidType(method.ReturnType)) { // don't write huge names. The debugger chokes on them and shows no locals at all. // result = new Local(Identifier.For("Contract.Result<" + typeName + ">()"), method.ReturnType); result = new Local(Identifier.For("Contract.Result()"), method.ReturnType); if (method.LocalList == null) { method.LocalList = new LocalList(); } method.LocalList.Add(result); } Block newExit = new Block(new StatementList()); #endregion Modify method body to change all returns into assignments and branch to unified exit #region Create the new method's body Block newBody = new Block(new StatementList()); newBody.HasLocals = true; #endregion Create the new method's body #region If there had been any closure initialization code, put it first in the new body if (0 < contractInitializationBlocks.Count) { foreach (Block b in contractInitializationBlocks) { newBody.Statements.Add(b); } } #endregion EmitInterleavedValidationsAndRequires(method, preconditions, validations, newBody); #region Turn off invariant checking until the end Local oldReEntrancyFlagLocal = null; if (MethodShouldHaveInvariantChecked(method) && this.ReentrancyFlag != null && BodyHasCalls(method.Body)) { oldReEntrancyFlagLocal = new Local(SystemTypes.Boolean); newBody.Statements.Add(new Block(new StatementList( new AssignmentStatement(oldReEntrancyFlagLocal, new MemberBinding(method.ThisParameter, this.ReentrancyFlag)), new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), Literal.True)))); } #endregion #region Put all of the collected initializations from "old" expressions into the method if (oldExpressionPreStateValues.Statements.Count > 0) { newBody.Statements.Add(oldExpressionPreStateValues); } #endregion // if there are preamble blocks we need to move them from the origBody in case we will wrap a try-catch var preambleIndex = 0; while (origBody.Statements.Count > preambleIndex && origBody.Statements[preambleIndex] is PreambleBlock) { newBody.Statements.Add(origBody.Statements[preambleIndex]); origBody.Statements[preambleIndex] = null; preambleIndex++; } Block newBodyBlock = new Block(new StatementList()); newBody.Statements.Add(newBodyBlock); // placeholder for eventual body newBody.Statements.Add(newExit); #region Replace "result" in postconditions (both for method return and out parameters) if (result != null) { foreach (Ensures e in postconditions) { if (e == null) continue; ReplaceResult repResult = new ReplaceResult(method, result, this.assemblyBeingRewritten); repResult.Visit(e); // now need to initialize closure result fields foreach (var target in repResult.NecessaryResultInitialization(closureLocals)) { newBody.Statements.Add(new AssignmentStatement(target, result)); } } } #endregion #region Emit potential post preamble block (from contract duplicate) in constructors if (postPreambleBlock != null) { newBody.Statements.Add(postPreambleBlock); } #endregion #region Emit normal postconditions SourceContext lastEnsuresSourceContext = default(SourceContext); bool hasLastEnsuresContext = false; bool containsExceptionalPostconditions = false; var ensuresChecks = new StatementList(); foreach (Ensures e in postconditions) { // Exceptional postconditions are handled separately. if (e is EnsuresExceptional) { containsExceptionalPostconditions = true; continue; } lastEnsuresSourceContext = e.SourceContext; hasLastEnsuresContext = true; // call Contract.RewriterEnsures Method ensMethod = this.runtimeContracts.EnsuresMethod; ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } ensuresChecks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, ensMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); } this.cleanUpCodeCoverage.VisitStatementList(ensuresChecks); EmitRecursionGuardAroundChecks(method, newBody, ensuresChecks); #endregion Normal postconditions #region Emit object invariant if (MethodShouldHaveInvariantChecked(method)) { // Now turn checking on by restoring old reentrancy flag if (this.ReentrancyFlag != null && oldReEntrancyFlagLocal != null) { newBody.Statements.Add(new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), oldReEntrancyFlagLocal)); } var callType = (method is InstanceInitializer) || this.InvariantMethod.DeclaringType.IsValueType ? NodeType.Call : NodeType.Callvirt; // just add a call to the already existing invariant method, "this.InvariantMethod();" // all of the processing needed is done as part of VisitClass newBody.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(method.ThisParameter, this.InvariantMethod), null, callType, SystemTypes.Void))); } #endregion Object invariant #region Emit exceptional postconditions ReplaceReturns rr; if (containsExceptionalPostconditions) { // -- The following code comes from System.Compiler.Normalizer.CreateTryCatchBlock -- // The tryCatch holds the try block, the catch blocks, and an empty block that is the // target of an unconditional branch for normal execution to go from the try block // around the catch blocks. if (method.ExceptionHandlers == null) method.ExceptionHandlers = new ExceptionHandlerList(); Block afterCatches = new Block(new StatementList()); Block tryCatch = newBodyBlock; Block tryBlock = new Block(new StatementList()); tryBlock.Statements.Add(origBody); rr = new ReplaceReturns(result, newExit, leaveExceptionBody:true); rr.Visit(origBody); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); // the EH needs to have a pointer to this block so the writer can // calculate the length of the try block. So it should be the *last* // thing in the try body. Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(blockAfterTryBody); tryCatch.Statements.Add(tryBlock); for (int i = 0, n = postconditions.Count; i < n; i++) { // Normal postconditions are handled separately. EnsuresExceptional e = postconditions[i] as EnsuresExceptional; if (e == null) continue; // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. Block catchBlock = new Block(new StatementList()); Local l = new Local(e.Type); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; // call Contract.RewriterEnsures ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } args.Add(l); var checks = new StatementList(); checks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, this.runtimeContracts.EnsuresOnThrowMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); catchBlock.Statements.Add(new AssignmentStatement(l, new Expression(NodeType.Pop), e.SourceContext)); this.cleanUpCodeCoverage.VisitStatementList(checks); EmitRecursionGuardAroundChecks(method, catchBlock, checks); #region Emit object invariant on EnsuresOnThrow check if (MethodShouldHaveInvariantChecked(method, inExceptionCase: true)) { // Now turn checking on by restoring old reentrancy flag if (this.ReentrancyFlag != null && oldReEntrancyFlagLocal != null) { catchBlock.Statements.Add(new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), oldReEntrancyFlagLocal)); } // just add a call to the already existing invariant method, "this.InvariantMethod();" // all of the processing needed is done as part of VisitClass catchBlock.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(method.ThisParameter, this.InvariantMethod), null, NodeType.Call, SystemTypes.Void))); } #endregion Object invariant catchBlock.Statements.Add(rethrow); // The last thing in each catch block is an empty block that is the target of // BlockAfterHandlerEnd in each exception handler. // It is used in the writer to determine the length of each catch block // so it should be the last thing added to each catch block. Block blockAfterHandlerEnd = new Block(new StatementList()); catchBlock.Statements.Add(blockAfterHandlerEnd); tryCatch.Statements.Add(catchBlock); // add information to the ExceptionHandlers of this method ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = origBody; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = blockAfterHandlerEnd; exHandler.FilterType = l.Type; exHandler.HandlerType = NodeType.Catch; method.ExceptionHandlers.Add(exHandler); } tryCatch.Statements.Add(afterCatches); } else // no exceptional post conditions { newBodyBlock.Statements.Add(origBody); rr = new ReplaceReturns(result, newExit, leaveExceptionBody: false); rr.Visit(origBody); } #endregion Exceptional and finally postconditions #region Create a block for the return statement and insert it // this is the block that contains the return statements // it is (supposed to be) the single exit from the method // that way, anything that must always be done can be done // in this block Block returnBlock = new Block(new StatementList(1)); if (asyncPostconditions != null && asyncPostconditions.Count > 0) { asyncBuilder.AddAsyncPost(asyncPostconditions); var funcLocal = new Local(asyncBuilder.FuncCtor.DeclaringType); var ldftn = new UnaryExpression(new MemberBinding(null, asyncBuilder.CheckMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); returnBlock.Statements.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, asyncBuilder.FuncCtor), new ExpressionList(asyncBuilder.ClosureLocal, ldftn)))); returnBlock.Statements.Add(new AssignmentStatement(result, new MethodCall(new MemberBinding(result, asyncBuilder.ContinueWithMethod), new ExpressionList(funcLocal)))); } Statement returnStatement; if (!HelperMethods.IsVoidType(method.ReturnType)) { returnStatement = new Return(result); } else { returnStatement = new Return(); } if (hasLastEnsuresContext) { returnStatement.SourceContext = lastEnsuresSourceContext; } else { returnStatement.SourceContext = rr.LastReturnSourceContext; } returnBlock.Statements.Add(returnStatement); newBody.Statements.Add(returnBlock); #endregion method.Body = newBody; #region Make sure InitLocals is marked for this method // 15 April 2003 // Since each method has locals added to it, need to make sure this flag is // on. Otherwise, the generated code cannot pass peverify. if (!method.InitLocals) { method.InitLocals = true; //WriteToLog("Setting InitLocals for method: {0}", method.FullName); } #endregion }
public void AddAsyncPost(List<Ensures> asyncPostconditions) { var origBody = new Block(this.checkBody); origBody.HasLocals = true; var newBodyBlock = new Block(new StatementList()); newBodyBlock.HasLocals = true; var methodBody = new StatementList(); var methodBodyBlock = new Block(methodBody); methodBodyBlock.HasLocals = true; checkMethod.Body = methodBodyBlock; methodBody.Add(newBodyBlock); Block newExitBlock = new Block(); methodBody.Add(newExitBlock); #region Map closure locals to fields and initialize closure fields foreach (Ensures e in asyncPostconditions) { if (e == null) continue; this.Visit(e); if (this.forwarder != null) { this.forwarder.Visit(e); } ReplaceResult repResult = new ReplaceResult(this.checkMethod, this.originalResultLocal, this.parent.assemblyBeingRewritten); repResult.Visit(e); // now need to initialize closure result fields foreach (var target in repResult.NecessaryResultInitializationAsync(this.closureLocals)) { // note: target here methodBody.Add(new AssignmentStatement(target, this.originalResultLocal)); } } #endregion #region Emit normal postconditions SourceContext lastEnsuresSourceContext = default(SourceContext); bool hasLastEnsuresContext = false; bool containsExceptionalPostconditions = false; var ensuresChecks = new StatementList(); foreach (Ensures e in asyncPostconditions) { // Exceptional postconditions are handled separately. if (e is EnsuresExceptional) { containsExceptionalPostconditions = true; continue; } if (IsVoidTask()) break; // something is wrong in the original contract lastEnsuresSourceContext = e.SourceContext; hasLastEnsuresContext = true; // call Contract.RewriterEnsures Method ensMethod = this.parent.runtimeContracts.EnsuresMethod; ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } ensuresChecks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, ensMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); } this.parent.cleanUpCodeCoverage.VisitStatementList(ensuresChecks); this.parent.EmitRecursionGuardAroundChecks(this.checkMethod, methodBodyBlock, ensuresChecks); #endregion Normal postconditions #region Exceptional postconditions if (containsExceptionalPostconditions) { // Because async tasks wrap exceptions into Aggregate exceptions, we have to catch AggregateException // and iterate over the internal exceptions of the Aggregate. // We thus emit the following handler: // // catch(AggregateException ae) { // ae.Handle(this.CheckException); // rethrow; // } // // alternatively, if the Task has no Result, we emit // // var ae = t.Exception as AggregateException; // if (ae != null) { // ae.Handle(this.CheckException); // throw ae; // } var aggregateType = AggregateExceptionType.Value; var exnParameter = new Parameter(Identifier.For("e"), SystemTypes.Exception); this.checkExceptionMethod = new Method(this.closureClass, null, this.checkExceptionMethodId, new ParameterList(exnParameter), SystemTypes.Boolean, new Block(new StatementList())); this.checkExceptionMethod.Body.HasLocals = true; checkExceptionMethod.CallingConvention = CallingConventionFlags.HasThis; checkExceptionMethod.Flags |= MethodFlags.Public; this.closureClass.Members.Add(checkExceptionMethod); if (this.IsVoidTask()) { var blockAfterTest = new Block(); methodBody.Add(origBody); methodBody.Add(new Branch(new UnaryExpression(this.newResultLocal, NodeType.LogicalNot), blockAfterTest)); var funcType = Func2Type.Value; funcType = funcType.GetTemplateInstance(this.parent.assemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression(new MemberBinding(null, this.checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); methodBody.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(this.checkMethod.ThisParameter, ldftn)))); methodBody.Add(new ExpressionStatement(new MethodCall(new MemberBinding(this.newResultLocal, handleMethod), new ExpressionList(funcLocal)))); methodBody.Add(new Throw(this.newResultLocal)); methodBody.Add(blockAfterTest); } else { // The tryCatch holds the try block, the catch blocks, and an empty block that is the // target of an unconditional branch for normal execution to go from the try block // around the catch blocks. if (this.checkMethod.ExceptionHandlers == null) this.checkMethod.ExceptionHandlers = new ExceptionHandlerList(); Block afterCatches = new Block(new StatementList()); Block tryCatch = newBodyBlock; Block tryBlock = new Block(new StatementList()); tryBlock.Statements.Add(origBody); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); // the EH needs to have a pointer to this block so the writer can // calculate the length of the try block. So it should be the *last* // thing in the try body. Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(blockAfterTryBody); tryCatch.Statements.Add(tryBlock); // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. Block catchBlock = new Block(new StatementList()); Local l = new Local(aggregateType); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(new AssignmentStatement(l, new Expression(NodeType.Pop))); var funcType = Func2Type.Value; funcType = funcType.GetTemplateInstance(this.parent.assemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression(new MemberBinding(null, this.checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); catchBlock.Statements.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(this.checkMethod.ThisParameter, ldftn)))); catchBlock.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(l, handleMethod), new ExpressionList(funcLocal)))); // Handle method should return if all passes catchBlock.Statements.Add(rethrow); // The last thing in each catch block is an empty block that is the target of // BlockAfterHandlerEnd in each exception handler. // It is used in the writer to determine the length of each catch block // so it should be the last thing added to each catch block. Block blockAfterHandlerEnd = new Block(new StatementList()); catchBlock.Statements.Add(blockAfterHandlerEnd); tryCatch.Statements.Add(catchBlock); // add information to the ExceptionHandlers of this method ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = origBody; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = blockAfterHandlerEnd; exHandler.FilterType = l.Type; exHandler.HandlerType = NodeType.Catch; this.checkMethod.ExceptionHandlers.Add(exHandler); tryCatch.Statements.Add(afterCatches); } EmitCheckExceptionBody(asyncPostconditions); } else // no exceptional post conditions { newBodyBlock.Statements.Add(origBody); } #endregion Exceptional and finally postconditions #region Create a block for the return statement and insert it // this is the block that contains the return statements // it is (supposed to be) the single exit from the method // that way, anything that must always be done can be done // in this block Statement returnStatement; if (this.IsVoidTask()) { returnStatement = new Return(); } else { returnStatement = new Return(this.newResultLocal); } if (hasLastEnsuresContext) { returnStatement.SourceContext = lastEnsuresSourceContext; } Block returnBlock = new Block(new StatementList(1)); returnBlock.Statements.Add(returnStatement); methodBody.Add(returnBlock); #endregion }
public override Statement VisitThrow(Throw Throw) { if (Throw == null) return null; if (!(Throw.Expression is Identifier)) { this.HandleError(Throw.Expression, Error.InvalidExceptionExpression); return null; } AddExceptionName(((Identifier)Throw.Expression).Name); return Throw; }
public override Statement VisitThrow(Throw Throw) { if (Throw == null) return null; return base.VisitThrow((Throw)Throw.Clone()); }
private Throw ParseThrow(TokenSet followers){ Throw Throw = new Throw(); Throw.SourceContext = this.scanner.CurrentSourceContext; Debug.Assert(this.currentToken == Token.Throw); this.GetNextToken(); if (this.currentToken != Token.Semicolon){ Expression expr = Throw.Expression = this.ParseExpression(followers|Token.Semicolon); if (expr != null) Throw.SourceContext.EndPos = expr.SourceContext.EndPos; } this.SkipSemiColon(followers); return Throw; }
public override Statement VisitThrow(Throw Throw) { if (Throw == null) return null; return Throw; }
/// <param name="Throw">Cloned</param> public override Statement VisitThrow(Throw Throw) { Throw = (Throw)Throw.Clone(); if (Throw.Expression != null) { Throw.Expression = simplify(Throw.Expression); } return Throw; }
public override Statement VisitThrow(Throw Throw) { this.lastBranchWasUnconditional = true; return Throw; }
// After they have been duplicated for each "leave" instruction, the "finally" // handlers are transformed into catch handlers that rethrow their exceptions. // public void ConvertFinallyHandlerIntoCatchHandler () { foreach (ExceptionHandler eh in this.allExceptionHandlers) { if (eh.HandlerType == NodeType.Finally || eh.HandlerType == NodeType.FaultHandler) { // transform the finally / fault handler into a catch handler ... eh.HandlerType = NodeType.Catch; // ... that catches all exceptions ... (cont'd at alpha) // (btw: in MSIL, one can throw any object, including non-Exceptions) eh.FilterType = Cci.SystemTypes.Object; // variable to store the caught exception (we can't leave it on the stack because the // code of the original finally handler must start with an empty stack). Variable exceptionVariable = new Local(new Identifier(FINALLYVARPREFIX + (finally_var_count++)), eh.FilterType); // the new catch handler must start with FINALLYVARPREFIX<n> := EPOP ... Block firstBlock = eh.HandlerStartBlock; StatementList stats = firstBlock.Statements; StatementList newBlockStatements = new StatementList(); AssignmentStatement exceptionAssignment = new AssignmentStatement(exceptionVariable, new Expression(NodeType.Pop)); if (stats.Count > 0) { exceptionAssignment.SourceContext = stats[0].SourceContext; exceptionAssignment.Source.SourceContext = stats[0].SourceContext; } newBlockStatements.Add(exceptionAssignment); for(int i = 0; i < stats.Count; i++) { newBlockStatements.Add(stats[i]); } firstBlock.Statements = newBlockStatements; // (alpha) ... and rethrows the exception. // replace the last instruction of eh with a throw exceptionVariable Block lastBlock = (Block) this.lastHandledBlock[eh]; Statement lastStatement = lastBlock.Statements[lastBlock.Statements.Count - 1]; if (lastStatement is EndFinally) { // replace the endfinally with a rethrow; this is OK because (re)throw flushes the stack too. Statement throwStatement; { #if EXPLICIT_THROW_OF_CAPTURED_VARIABLE_RATHER_THAN_RETHROW_IN_FINALLY_EXPANDED_CATCH if (false) // for now { throwStatement = new Throw(exceptionVariable); } else #endif throwStatement = new Throw(null); throwStatement.NodeType = NodeType.Rethrow; } throwStatement.SourceContext = lastBlock.Statements[lastBlock.Statements.Count - 1].SourceContext; lastBlock.Statements[lastBlock.Statements.Count - 1] = throwStatement; } else { Debug.Assert(lastStatement is Throw, "finally/fault not terminated in endfinally/endfault or throw! " + CodePrinter.StatementToString(lastBlock.Statements[lastBlock.Statements.Count - 1])); } } } }
public override Statement VisitThrow(Throw Throw) { Statement setExceptionStmt = Templates.GetStatementTemplate("SetException"); Debug.Assert(Throw.Expression is Identifier); Replacer.Replace(setExceptionStmt, "_exception", Throw.Expression); BasicBlock raiseBlock = new BasicBlock(null); raiseBlock.SkipNormalizer = true; raiseBlock.SourceContext = Throw.SourceContext; raiseBlock.MiddleOfTransition = true; AddBlock(raiseBlock); if (this.CurrentHandlerBlock != null) { // If we have a handler, pass control locally raiseBlock.Statement = setExceptionStmt; raiseBlock.UnconditionalTarget = this.CurrentHandlerBlock; } else { // No local handler, so propagate outward immediately. Block b = new Block(new StatementList()); b.Statements.Add(setExceptionStmt); b.Statements.Add(Templates.GetStatementTemplate("PropagateException")); raiseBlock.Statement = b; raiseBlock.PropagatesException = true; } CurrentContinuation = raiseBlock; return Throw; }
public override Statement VisitThrow(Throw Throw) { // The base Checker will complain that we haven't resolved Throw.Expression // but for us that's ok because exceptions are just names. return Throw; }
public override Statement VisitThrow(Throw Throw) { WriteStart("throw"); if (Throw.Expression != null) { Write(" "); this.VisitExpression(Throw.Expression); } WriteFinish(";"); return Throw; }
public EventingVisitor(Action<Throw> visitThrow) { VisitedThrow += visitThrow; } public event Action<Throw> VisitedThrow; public override Statement VisitThrow(Throw Throw) { if (VisitedThrow != null) VisitedThrow(Throw); return base.VisitThrow(Throw); }