Пример #1
0
        internal static Block CreateTryFinallyBlock(Method method, Block tryBody, Block finallyBody)
        {
          Contract.Requires(method != null);
          Contract.Requires(tryBody != null);
          Contract.Requires(finallyBody != null);

            if (method.ExceptionHandlers == null) method.ExceptionHandlers = new ExceptionHandlerList();

            Block result = new Block(new StatementList());
            Block afterFinally = new Block(new StatementList());

            tryBody.Statements.Add(new Branch(null, afterFinally, false, true, true));
            finallyBody.Statements.Add(new EndFinally());

            result.Statements.Add(tryBody);
            result.Statements.Add(finallyBody);
            result.Statements.Add(afterFinally);

            ExceptionHandler fb = new ExceptionHandler();
            fb.TryStartBlock = tryBody;
            fb.BlockAfterTryEnd = finallyBody;
            fb.HandlerStartBlock = finallyBody;
            fb.BlockAfterHandlerEnd = afterFinally;
            fb.HandlerType = NodeType.Finally;
            method.ExceptionHandlers.Add(fb);

            return result;
        }
Пример #2
0
    private void EmitRecursionGuardAroundChecks(Method method, Block newBody, StatementList checks)
    {
      StatementList stmts = new StatementList();
      Block preconditionsStart = new Block(stmts);
      Block finallyStart = null;
      Block finallyEnd = new Block(); // branch target for skipping the checks

      // test if we are an auto property and need to disable the check if we are in construction
      if (this.ReentrancyFlag != null && (method.IsPropertyGetter || method.IsPropertySetter) && HelperMethods.IsAutoPropertyMember(method) && !method.IsStatic) {
        newBody.Statements.Add(new Branch(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), finallyEnd));
      }

      // don't add try finally if there are no precondition or if the method is a constructor (peverify issue)
      if (NeedsRecursionGuard(method, checks))
      {
        // emit recursion check
        finallyStart = new Block(new StatementList());

        // if (insideContractEvaluation > $recursionGuard$) goto finallyEnd
        // try {
        //   insideContractEvaluation++;
        //   checks;
        //   leave;
        // } finally {
        //   insideContractEvaluation--;
        // }
        //
        // SPECIAL CASE for auto properties where we made invariants into pre/post, we need to avoid the check if we are 
        // evaluating the invariant.
        //
        // if (this.$evaluatingInvariant || insideContractEvaluation > $recursionGuard$) goto finallyEnd
        // 

        newBody.Statements.Add(new Branch(new BinaryExpression(new MemberBinding(null, this.runtimeContracts.InContractEvaluationField), new Literal(this.runtimeContracts.RecursionGuardCountFor(method), SystemTypes.Int32), NodeType.Gt), finallyEnd));

        stmts.Add(new AssignmentStatement(new MemberBinding(null, this.runtimeContracts.InContractEvaluationField),
                                          new BinaryExpression(new MemberBinding(null, this.runtimeContracts.InContractEvaluationField), Literal.Int32One, NodeType.Add)));
        stmts.Add(new Block(checks));
        var leave = new Branch();
        leave.Target = finallyEnd;
        leave.LeavesExceptionBlock = true;
        stmts.Add(leave);
        
        finallyStart.Statements.Add(new AssignmentStatement(new MemberBinding(null, this.runtimeContracts.InContractEvaluationField),
                                    new BinaryExpression(new MemberBinding(null, this.runtimeContracts.InContractEvaluationField), Literal.Int32One, NodeType.Sub)));

        finallyStart.Statements.Add(new EndFinally());
      }
      else
      {
        stmts.Add(new Block(checks));
      }

      newBody.Statements.Add(preconditionsStart);
      if (finallyStart != null)
      {
        newBody.Statements.Add(finallyStart);
        var finallyHandler = new ExceptionHandler();
        finallyHandler.TryStartBlock = preconditionsStart;
        finallyHandler.BlockAfterTryEnd = finallyStart;
        finallyHandler.HandlerStartBlock = finallyStart;
        finallyHandler.BlockAfterHandlerEnd = finallyEnd;
        finallyHandler.HandlerType = NodeType.Finally;

        method.ExceptionHandlers.Add(finallyHandler);
      }
      // branch target for skipping the checks
      newBody.Statements.Add(finallyEnd);
    }
Пример #3
0
    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;
    }
Пример #4
0
    //[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
    }
Пример #5
0
        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
        }
Пример #6
0
      private void DuplicateFinallyBody (
        ExceptionHandler eh, 
        Block leave_block,
        out Block startBlock,
        out Block lastBlock
        ) {
        Hashtable/*<Block,Block>*/ orig2copy = new Hashtable();

        Block hdlr_last_block;
        ISet/*<Block>*/ handler_body = GetFinallyBody(eh, out hdlr_last_block);

        foreach(Block orig_block in handler_body) {
          Block clone_block = dupVisitor.VisitBlock(orig_block);
          this.copy2orig.Add(clone_block, orig_block);
          orig2copy.Add(orig_block, clone_block);

          if (ControlFlowGraph.FINALLY_CLONE_DEBUG) {
            this.cfg.b2cloning_leave[clone_block] = leave_block;
          }

          /*
          Console.Out.WriteLine("cloning {0} -> {1}",
            CodePrinter.b2s(orig_block), CodePrinter.b2s(clone_block));
            */

          this.new_blocks.Add(clone_block);
        }

        CorrectBranchVisitor correctBranchVisitor = new CorrectBranchVisitor(orig2copy);

        foreach(Block orig_block in handler_body) {
          Block clone_block = (Block) orig2copy[orig_block];

          //Console.Out.WriteLine("Fixing branching instructions from " + CodePrinter.b2s(clone_block));

          correctBranchVisitor.VisitBlock(clone_block);

          //Console.Out.WriteLine("Fixing handlers for " + CodePrinter.b2s(clone_block));

          FixExceptionalSuccessorForClone(orig_block, clone_block, orig2copy);
          AddHandlerIfClonedBlockStartsHandler(eh, orig_block, clone_block, orig2copy);

          // fix_block2next unless it's the last block or a definite branch. Otherwise block2next is not linear
          if (orig_block != hdlr_last_block) {
            Block orig_next = (Block) block2next[orig_block];
            if (orig_next != null) {
              Block newNext = Convert(orig_next, orig2copy);
              if (newNext != orig_next) {
                block2next[clone_block] = newNext;
              }
            }
          }
        }
				
        // 2nd fixup pass to adjust containing_handler map
        // this cannot be done in previous loop, since the previous loop
        // builds the clones of the handlers.
        //
        Block finallyStart = eh.HandlerStartBlock;
        ExceptionHandler origContainingHandlerOfFinally = (ExceptionHandler)this.cfg.b2_containing_handler[finallyStart]; //MayBeNull

        foreach(Block orig_block in handler_body) {
          Block clone_block = (Block) orig2copy[orig_block];

          ExceptionHandler ceh = (ExceptionHandler) this.cfg.b2_containing_handler[orig_block];
          if (ceh != null) {
            ExceptionHandler eh_clone = (ExceptionHandler) orig2copy[ceh];
            if (eh_clone == null) {
              this.cfg.b2_containing_handler[clone_block] = ceh;
            }
            else {
              this.cfg.b2_containing_handler[clone_block] = eh_clone;
            }
          }


          // the orig_blocks will become part of a new exception handler, so
          // we also need to redirect their containing_handler to the eh (currently a finally) 
          // that will be turned into an exception handler
          // We do this by looking up the containing handler of the finally first block, then
          // changing every block in the finally whose containing handler is the same to the new handler.
          if (ceh == origContainingHandlerOfFinally) {
            this.cfg.b2_containing_handler[orig_block] = eh;
          }
        }

        startBlock = (Block) orig2copy[eh.HandlerStartBlock];
        lastBlock = (Block) orig2copy[hdlr_last_block];
        Debug.Assert(startBlock != null && lastBlock != null);

      }
Пример #7
0
 public virtual ExceptionHandler VisitExceptionHandler(ExceptionHandler handler)
 {
     if (handler == null) return null;
     handler = (ExceptionHandler)handler.Clone();
     handler.BlockAfterHandlerEnd = this.VisitBlock(handler.BlockAfterHandlerEnd);
     handler.BlockAfterTryEnd = this.VisitBlock(handler.BlockAfterTryEnd);
     handler.FilterExpression = this.VisitBlock(handler.FilterExpression);
     handler.FilterType = this.VisitTypeReference(handler.FilterType);
     handler.HandlerStartBlock = this.VisitBlock(handler.HandlerStartBlock);
     handler.TryStartBlock = this.VisitBlock(handler.TryStartBlock);
     return handler;
 }
Пример #8
0
 private void add_try_start(ExceptionHandler eh, Hashtable/*<Block,Stack<ExceptionHandler>>*/ b2start) {
   Block eh_start = eh.TryStartBlock;
   Stack starts = (Stack) b2start[eh_start];
   if (starts == null)
     b2start.Add(eh_start, starts = new Stack());
   starts.Push(eh);
 }
Пример #9
0
 private void add_handler_end(ExceptionHandler eh, Hashtable/*<Block,Queue<ExceptionHandler>>*/ b2end) {
   Block eh_end = eh.BlockAfterHandlerEnd;
   Queue ends = (Queue) b2end[eh_end];
   if (ends == null)
     b2end.Add(eh_end, ends = new Queue());
   ends.Enqueue(eh);
 }
Пример #10
0
    /// <summary>
    /// Computes the ExceptionHandler for each block and the chaining of exception handlers.
    /// Note: 
    ///   Filter handlers are currently treated as starting at the filter expression
    ///   and the endfilter is like a fall through into the actual handler.
    /// </summary>
    private bool examine_real_excp_flow(Method method, ExceptionHandlerList ehs, StatementList blocks,
      out IList/*<ExceptionHandler>*/ all_ehs) {
      bool has_finally = false;
      b2exception_handler = new Hashtable();
      all_ehs      = new ArrayList();
      this.handlerThatStartsAtBlock = new Hashtable();
      Hashtable/*<Block,Stack<ExceptionHandler>>*/ b2start = new Hashtable();
      Hashtable/*<Block,Queue<ExceptionHandler>>*/ b2end   = new Hashtable();
      Hashtable/*<Block,Queue<ExceptionHandler>>*/ b2handler_end = new Hashtable();

      // records for each exception handler, the exception handler tried next
      e2_next = new Hashtable();
      b2_enclosing_finally = new Hashtable();
      b2_containing_handler = new Hashtable();

      for(int i = 0; i < ehs.Count; i++) {
        ExceptionHandler eh = ehs[i];
        all_ehs.Add(eh);
        if (eh.HandlerType == NodeType.Finally)
          has_finally = true;
        if (eh.HandlerType == NodeType.Filter) {
          /*
           * WE NEED TO HANDLE Filter exceptions to do Visual Basic
           * 
          throw new UnsupportedCodeException(method, "Filter exception handler");
          */
          // we pretend the filter block is a catch block
          // for uniform processing while flattening
          // i.e. it's a block that starts with an implicit
          // push of the exception, just like a handler.

          // HACK, we reverse the FilterExpression and HandlerStart so that
          // We treat the entire filter as a handler
          Block filter = eh.FilterExpression;
          eh.FilterExpression = eh.HandlerStartBlock;
          eh.HandlerStartBlock = filter;
        }
        this.handlerThatStartsAtBlock[eh.HandlerStartBlock] = eh;

        add_try_start(eh, b2start);
        add_try_end(eh, b2end);
        add_handler_end(eh, b2handler_end);
      }

      FList/*<ExceptionHandler>*/ handlers = FList.Empty; // protecting the current block
      FList/*<ExceptionHandler>*/ finallies = FList.Empty; // protecting the current block
      FList/*<ExceptionHandler>*/ containingHandlers = FList.Empty; // containing the current block (top) is current (non-finally)

      // Push the implicit exceptional exit handler at the bottom of the stack
      ExceptionHandler handler_around_entire_method = new ExceptionHandler();
      handler_around_entire_method.HandlerStartBlock = excp_exit_point;
      handlers = FList.Cons(handler_around_entire_method, handlers);

      for(int i = 0; i < blocks.Count; i++) {
        Block block = (Block) blocks[i];

        // pop protecting handlers off stack whose scope ends here
        Queue ends = (Queue) b2end[block];
        if (ends != null)
          foreach(ExceptionHandler eh in ends) {
            if (eh == handlers.Head)
              handlers = handlers.Tail; // Pop handler
            else
              throw new ApplicationException("wrong handler");

            if (eh.HandlerType == NodeType.Finally) {
              if (eh == finallies.Head) {
                finallies = finallies.Tail; // Pop finally
              }
              else
                throw new ApplicationException("wrong finally on stack");
            }
          }

        // push protecting handlers on stack whose scope starts here
        Stack starts = (Stack) b2start[block];
        if (starts != null) {
          foreach(ExceptionHandler eh in starts) {
            ExceptionHandler enclosing = (ExceptionHandler)handlers.Head;

            // push this handler on top of current block enclosing handlers
            handlers = FList.Cons(eh, handlers); // Push handler

            // also record the next enclosing handler for this handler.
            e2_next[eh.HandlerStartBlock] = enclosing.HandlerStartBlock;

            // also keep stack of finallies
            if (eh.HandlerType == NodeType.Finally) {
              finallies = FList.Cons(eh, finallies);
            }
          }
        }

        // pop containing handlers off containing stack whose handler scope ends here
        Queue handler_ends = (Queue) b2handler_end[block];
        if (handler_ends != null) {
          foreach(ExceptionHandler eh in handler_ends) {
            if (eh == containingHandlers.Head) {
              containingHandlers = containingHandlers.Tail; // Pop containingHandler
            }
            else {
              throw new ApplicationException("wrong containingHandler on stack");
            }
          }
        }
        // push containing handler on stack whose handler scope starts here
        ExceptionHandler seh = (ExceptionHandler) this.handlerThatStartsAtBlock[block];
        if (seh != null) {
          containingHandlers = FList.Cons(seh, containingHandlers);
        }

        // We now add a single exceptional successor, which is the closest enclosing one.
        ExceptionHandler topeh = (ExceptionHandler)handlers.Head;

        b2exception_handler.Add(block, topeh.HandlerStartBlock);

        // We also store the enclosing finally list
        b2_enclosing_finally.Add(block, finallies);

        // We also store the map block -> exception handler containing block in handler
        if (containingHandlers != null) {
          b2_containing_handler.Add(block, containingHandlers.Head);
        }
      }
      return has_finally;
    }
Пример #11
0
      // Finds the last block of the ExceptionHandler eh of Method method.
      private Block LastBlockInsideHandler (ExceptionHandler eh) {
        if ( ! this.b2index.ContainsKey(eh.BlockAfterHandlerEnd)) {
          // Apparently, some methods (e.g. System.Management.MTAHelper.WorkerThread 
          // in System.Management.dll) have a handler end block that names
          // a label (instruction number) beyond the last instruction
          // (presumably to refer to the end of the method). Naturally, this block
          // representing this handler end block isn't part of the method body
          // because it doesn't actually exist. So we artificially add it.
          method.Body.Statements.Add(eh.BlockAfterHandlerEnd);
          this.b2index[eh.BlockAfterHandlerEnd] = method.Body.Statements.Count - 1;

          Debug.Assert(eh.BlockAfterHandlerEnd.Statements.Count == 0); 
          // Can't allow completely empty block.
          eh.BlockAfterHandlerEnd.Statements.Add(new Return());
        }

        int i = (int) this.b2index[eh.BlockAfterHandlerEnd];
        return (Block) method.Body.Statements[i-1];
      }
Пример #12
0
      // if a handler starts at orig_block, a cloned handler starts at clone_block.
      //
      private void AddHandlerIfClonedBlockStartsHandler (
        ExceptionHandler current_eh,
        Block originalBlock, 
        Block blockCopy, 
        Hashtable/*<Block,Block>*/ orig2copy
        ) {
        ExceptionHandler eh = (ExceptionHandler) this.cfg.handlerThatStartsAtBlock[originalBlock];
        // The current finally handler is not duplicated (as a handler).  It is now part of
        // the execution path that replaced some leave instruction, not an exception handler.
        if ((eh == null) || (eh == current_eh)) return;

        ExceptionHandler clonedHandler = (ExceptionHandler) eh.Clone();

        // store the mapping from orig handler to cloned handler in orig2copy (yes, we are overloading this block->block map
        // with eh -> eh mappings.
        // We need this so we can adjust the containingHandler of copied blocks.
        orig2copy[eh] = clonedHandler;

        if (eh.FilterExpression != null) {
          clonedHandler.FilterExpression = FindCopyOfBlock(eh.FilterExpression, orig2copy);
        }
        clonedHandler.HandlerStartBlock = FindCopyOfBlock(eh.HandlerStartBlock, orig2copy);
        clonedHandler.TryStartBlock  = FindCopyOfBlock(eh.TryStartBlock, orig2copy);
        /*
         * The problem with the following code was that the eh.BlockAfter(Handler/Try)End might not have
         * been cloned, so there no equivalent of it in the cloned world!  It would have been better
         * to identify a handler by its last block, not the first after last ...
        clonedHandler.BlockAfterHandlerEnd = FindCopyOfBlock(eh.BlockAfterHandlerEnd, orig2copy);
        clonedHandler.BlockAfterTryEnd     = FindCopyOfBlock(eh.BlockAfterTryEnd, orig2copy);
        if (eh.FilterExpresssion != null)
          clonedHandler.FilterExpresssion = ImperativeGetCopy(eh.FilterExpresssion, orig2copy);
        this.b2started_eh[blockCopy] = clonedHandler;
        */
        this.allExceptionHandlers.Add(clonedHandler);
        this.cfg.handlerThatStartsAtBlock[blockCopy] = clonedHandler;
        if (eh.HandlerType == NodeType.Finally) {
          this.lastHandledBlock[clonedHandler] = FindCopyOfBlock((Block) this.lastHandledBlock[eh], orig2copy);
        }

        // Sine we're introducing a new handler, we need to update the e2_next 
        // relation, since that determines how handlers are chained together.

        // Look up the handler invoked after the one being cloned.
        Block nextHandler = (Block) this.cfg.e2_next[eh.HandlerStartBlock];
        if (orig2copy.ContainsKey(nextHandler)) {
          // If that handler is also being cloned, chain to the 
          // clone rather than the original.
          nextHandler = (Block) orig2copy[nextHandler];
        }
        this.cfg.e2_next[clonedHandler.HandlerStartBlock] = nextHandler;
      }
Пример #13
0
 public AvoidClosure (FinallyBlockDuplicator parent, ExceptionHandler eh) {
   this.parent          = parent;
   this.orig_hdlr_start = (int) parent.b2index[eh.HandlerStartBlock];
   this.orig_hdlr_end   = (int) parent.b2index[eh.BlockAfterHandlerEnd] - 1;
 }
Пример #14
0
      // I wish C# had native support for tupples ...
      /*
      private class BlockPair 
      {
        public BlockPair(Block first, Block last) 
        {
          this.first = first;
          this.last  = last;
        }
        public Block first;
        public Block last;
      }
      */

      private ISet/*<Block>*/ GetFinallyBody (ExceptionHandler eh, out Block last_block) {
        StatementList blocks = method.Body.Statements;
        int hdlr_end_index = (int) b2index[eh.BlockAfterHandlerEnd];
        last_block = (Block) blocks[hdlr_end_index-1];
        ISet/*<Block>*/ handler_body = GraphUtil.ReachableNodes
          (DataStructUtil.NodeSetFactory, new Block[]{eh.HandlerStartBlock}, bnav,
          new DNodePredicate((new AvoidClosure(this, eh)).Avoid));
        // ^ isn't it ugly ?  what we need are first class functions ...

        /*
        Console.Out.WriteLine("handler_body(" + CodePrinter.b2s(eh.HandlerStartBlock) +
          ") = " + DataStructUtil.IEnum2String(handler_body, CodePrinter.BlockShortPrinter));
          */

        while ( ! handler_body.Contains(last_block)) {
          // Crap! The last syntactic block is dead (unreachable), so now
          // we need a substitute. We search backward until we find one.
          // This loop is guaranteed to terminate, since we'll eventually
          // get back to the handler start block, which is trivially reachable
          // from the handler start block.
          hdlr_end_index --;
          last_block = (Block) blocks[hdlr_end_index-1];
        }

        Debug.Assert(handler_body.Contains(last_block), "last block not in blocks reachable from start");
        return handler_body;
      }