Inheritance: IGenerator
Example #1
0
        /// <summary>
        /// Visits block statements and its edge to next block.
        /// </summary>
        protected virtual void VisitCFGBlockInternal(BoundBlock x)
        {
            VisitCFGBlockStatements(x);

            if (x.NextEdge != null)
                x.NextEdge.Visit(this);
        }
Example #2
0
        /// <summary>
        /// Subscribe a block to be analysed when the exit block is reached and the routine return value changes.
        /// </summary>
        internal void Subscribe(BoundBlock x)
        {
            if (_subscribers == null)
                _subscribers = new HashSet<BoundBlock>();

            _subscribers.Add(x);
        }
Example #3
0
 void VisitCFGBlockStatements(BoundBlock x)
 {
     for (int i = 0; i < x.Statements.Count; i++)
     {
         Accept(x.Statements[i]);
     }
 }
Example #4
0
 public virtual void VisitBlockStatement(Graph.BoundBlock x)
 {
     for (int i = 0; i < x.Statements.Count; i++)
     {
         Accept(x.Statements[i]);
     }
 }
Example #5
0
 protected virtual TResult DefaultVisitBlock(BoundBlock x) => default;
 public virtual void VisitBlockStatement(Graph.BoundBlock x)
 {
     x.Statements.ForEach(Accept);
 }
 public BreakTargetScope(BoundBlock breakBlock, BoundBlock continueBlock)
 {
     BreakTarget    = breakBlock;
     ContinueTarget = continueBlock;
 }
Example #8
0
 internal TryCatchEdge(BoundBlock source, BoundBlock body, CatchBlock[] catchBlocks, BoundBlock finallyBlock, BoundBlock endBlock)
     : base(source)
 {
     _body = body;
     _catchBlocks = catchBlocks;
     _finallyBlock = finallyBlock;
     _end = endBlock;
     Connect(source);
 }
Example #9
0
 internal LeaveEdge(BoundBlock source, BoundBlock target)
     :base(source, target)
 {
 }
Example #10
0
        /// <summary>
        /// Helper method that merges state with the target block and determines whether to continue by visiting the target block.
        /// </summary>
        /// <param name="state">Locals state in which we are entering the target.</param>
        /// <param name="target">Target block.</param>
        /// <remarks>Only for traversing into blocks within the same routine (same type context).</remarks>
        private void TraverseToBlock(FlowState/*!*/state, BoundBlock/*!*/target)
        {
            Contract.ThrowIfNull(state);    // state should be already set by previous block
            
            var targetState = target.FlowState;
            if (targetState != null)
            {
                Debug.Assert(targetState.FlowContext == state.FlowContext);

                // block was visited already,
                // merge and check whether state changed
                state = state.Merge(targetState);   // merge states into new one
                if (state.Equals(targetState))
                {
                    return; // state convergated, we don't have to analyse target block again
                }
            }
            else
            {
                // block was not visited yet
                state = state.Clone();              // copy state into new one
            }

            // update target block state
            target.FlowState = state;

            //
            _worklist.Enqueue(target);
        }
        public override void VisitSwitchStmt(SwitchStmt x)
        {
            var items = x.SwitchItems;

            if (items == null || items.Length == 0)
            {
                return;
            }

            // get bound item for switch value & connect potential pre-switch-value blocks
            var boundBagForSwitchValue = _binder.BindWholeExpression(x.SwitchValue, BoundAccess.Read);

            ConnectBoundItemsBagBlocksToCurrentBlock(boundBagForSwitchValue);
            var switchValue = boundBagForSwitchValue.BoundElement;

            var end = NewBlock();

            bool hasDefault = false;
            var  cases      = new List <CaseBlock>(items.Length);

            for (int i = 0; i < items.Length; i++)
            {
                cases.Add(NewBlock(items[i]));
                hasDefault |= (items[i] is DefaultItem);
            }
            if (!hasDefault)
            {
                // create implicit default:
                cases.Add(NewBlock(new DefaultItem(x.Span, Array.Empty <Statement>())));
            }

            // if switch value isn't a constant & there're case values with preBoundStatements
            // -> the switch value might get evaluated multiple times (see SwitchEdge.Generate) -> preemptively evaluate and cache it
            if (!switchValue.IsConstant() && !cases.All(c => c.CaseValue.IsOnlyBoundElement))
            {
                var result = GeneratorSemanticsBinder.CreateAndAssignSynthesizedVariable(switchValue, BoundAccess.Read, $"<switchValueCacher>{x.Span}");
                switchValue = result.BoundExpr;
                _current.Add(new BoundExpressionStatement(result.Assignment));
            }

            // SwitchEdge // Connects _current to cases
            var edge = new SwitchEdge(_current, switchValue, cases.ToImmutableArray(), end);

            _current = WithNewOrdinal(cases[0]);

            OpenBreakScope(end, end); // NOTE: inside switch, Continue ~ Break

            for (int i = 0; i < cases.Count; i++)
            {
                OpenScope(_current);

                if (i < items.Length)
                {
                    items[i].Statements.ForEach(VisitElement);  // any break will connect block to end
                }
                CloseScope();

                _current = WithNewOrdinal(Connect(_current, (i == cases.Count - 1) ? end : cases[i + 1]));
            }

            CloseBreakScope();

            Debug.Assert(_current == end);
        }
 private void OpenScope(BoundBlock block, LocalScope scope = LocalScope.Code)
 {
     _scopes.Push(new LocalScopeInfo(block, scope));
 }
 public LocalScopeInfo(BoundBlock firstBlock, LocalScope scope)
 {
     this.FirstBlock = firstBlock;
     this.Scope      = scope;
 }
 private BoundBlock /*!*/ Leave(BoundBlock /*!*/ source, BoundBlock /*!*/ target)
 {
     new LeaveEdge(source, target);
     return(target);
 }
 private BoundBlock /*!*/ Connect(BoundBlock /*!*/ source, BoundBlock /*!*/ target)
 {
     new SimpleEdge(source, target);
     return(target);
 }
        private BoundBlock /*!*/ Connect(BoundBlock /*!*/ source, BoundBlock /*!*/ ifTarget, BoundBlock /*!*/ elseTarget, Expression condition, bool isloop = false)
        {
            if (condition != null)
            {
                // bind condition expression & connect pre-condition blocks to source
                var boundConditionBag = _binder.BindWholeExpression(condition, BoundAccess.Read);
                source = ConnectBoundItemsBagBlocks(boundConditionBag, source);

                new ConditionalEdge(source, ifTarget, elseTarget, boundConditionBag.BoundElement)
                {
                    IsLoop = isloop,
                };

                return(ifTarget);
            }
            else
            {
                // jump to ifTarget if there is no condition (always true) // e.g. for (;;) { [ifTarget] }
                return(Connect(source, ifTarget));
            }
        }
 private void ConnectBoundItemsBagBlocksToCurrentBlock <T>(BoundItemsBag <T> bag) where T : class, IPhpOperation
 {
     _current = ConnectBoundItemsBagBlocks(bag, _current);
 }
Example #18
0
        /// <summary>
        /// Called to initialize <see cref="VisitCFGBlock"/> call.
        /// Sets <see cref="_state"/> to known initial block state.
        /// </summary>
        protected virtual void VisitCFGBlockInit(BoundBlock/*!*/x)
        {
            Contract.ThrowIfNull(x.FlowState);   // state should be already set by previous edge
            _state = x.FlowState.Clone();        // TFlowState for the statements in the block

            this.CurrentBlock = x;
        }
Example #19
0
 public override void VisitCFGBlock(BoundBlock x)
 {
     VisitCFGBlockInit(x);
     VisitCFGBlockInternal(x);   // modifies _state, traverses to the edge
 }
        public override void VisitTryStmt(TryStmt x)
        {
            // try {
            //   x.Body
            // }
            // catch (E1) { body }
            // catch (E2) { body }
            // finally { body }
            // end

            var end  = NewBlock();
            var body = NewBlock();

            // init catch blocks and finally block
            var catchBlocks = ImmutableArray <CatchBlock> .Empty;

            if (x.Catches != null)
            {
                var catchBuilder = ImmutableArray.CreateBuilder <CatchBlock>(x.Catches.Length);
                for (int i = 0; i < x.Catches.Length; i++)
                {
                    catchBuilder.Add(NewBlock(x.Catches[i]));
                }

                catchBlocks = catchBuilder.MoveToImmutable();
            }

            BoundBlock finallyBlock = null;

            if (x.FinallyItem != null)
            {
                finallyBlock = NewBlock();
            }

            // TryCatchEdge // Connects _current to body, catch blocks and finally
            var edge = new TryCatchEdge(_current, body, catchBlocks, finallyBlock, end);

            var oldstates0 = _binder.StatesCount;

            // build try body
            OpenTryScope(edge);
            OpenScope(body, LocalScope.Try);
            _current = WithNewOrdinal(body);
            VisitElement(x.Body);
            CloseScope();
            CloseTryScope();
            _current = Leave(_current, finallyBlock ?? end);

            var oldstates1 = _binder.StatesCount;

            // built catches
            for (int i = 0; i < catchBlocks.Length; i++)
            {
                _current = WithOpenScope(WithNewOrdinal(catchBlocks[i]), LocalScope.Catch);
                VisitElement(x.Catches[i].Body);
                CloseScope();
                _current = Leave(_current, finallyBlock ?? end);
            }

            // build finally
            var oldReturnCount = _returnCounter;

            if (finallyBlock != null)
            {
                _current = WithOpenScope(WithNewOrdinal(finallyBlock), LocalScope.Finally);
                VisitElement(x.FinallyItem.Body);
                CloseScope();
                _current = Leave(_current, end);
            }

            //
            if ((oldstates0 != oldstates1 && finallyBlock != null) ||   // yield in "try" with "finally" block
                oldstates1 != _binder.StatesCount ||                    // yield in "catch" or "finally"
                oldReturnCount != _returnCounter)                       // return in "finally"
            {
                // catch or finally introduces new states to the state machine
                // or there is "return" in finally block:

                // catch/finally must not be handled by CLR
                edge.EmitCatchFinallyOutsideScope = true;
            }

            // _current == end
            _current.Ordinal = NewOrdinal();
        }
Example #21
0
 internal SimpleEdge(BoundBlock source, BoundBlock target)
     : base(source)
 {
     Debug.Assert(source != target);
     _target = target;
     Connect(source);
 }
Example #22
0
        internal ForeachMoveNextEdge(BoundBlock/*!*/source, BoundBlock/*!*/body, BoundBlock/*!*/end, ForeachEnumereeEdge/*!*/enumereeEdge, BoundReferenceExpression keyVar, BoundReferenceExpression/*!*/valueVar)
            : base(source)
        {
            Contract.ThrowIfNull(body);
            Contract.ThrowIfNull(end);
            Contract.ThrowIfNull(enumereeEdge);

            _body = body;
            _end = end;
            _enumereeEdge = enumereeEdge;
            _keyVariable = keyVar;
            _valueVariable = valueVar;

            Connect(source);
        }
Example #23
0
        internal ConditionalEdge(BoundBlock source, BoundBlock @true, BoundBlock @false, BoundExpression cond)
            : base(source)
        {
            Debug.Assert(@true != @false);

            _true = @true;
            _false = @false;
            _condition = cond;

            Connect(source);
        }
Example #24
0
 internal Edge(BoundBlock/*!*/source)
 {
     Contract.ThrowIfNull(source);
 }
Example #25
0
 internal ForeachEnumereeEdge(BoundBlock/*!*/source, BoundBlock/*!*/target, BoundExpression/*!*/enumeree, bool aliasedValues)
     : base(source, target)
 {
     Contract.ThrowIfNull(enumeree);
     _enumeree = enumeree;
     _aliasedValues = aliasedValues;
 }
Example #26
0
 public virtual TResult VisitCFGBlock(BoundBlock x) => DefaultVisitBlock(x);
Example #27
0
        internal SwitchEdge(BoundBlock source, BoundExpression switchValue, CaseBlock[] caseBlocks, BoundBlock endBlock)
            : base(source)
        {
            Contract.ThrowIfNull(caseBlocks);
            _switchValue = switchValue;
            _caseBlocks = caseBlocks;
            _end = endBlock;

            Connect(source);
        }
Example #28
0
 public virtual void VisitCFGBlock(BoundBlock x)
 {
     VisitCFGBlockInternal(x);
 }
Example #29
0
 protected void Connect(BoundBlock/*!*/source)
 {
     source.NextEdge = this;
 }
Example #30
0
        void AnalyzeBlock(BoundBlock block) // TODO: driver
        {
            // TODO: pool of CFGAnalysis
            // TODO: async
            // TODO: in parallel

            block.Accept(AnalysisFactory());
        }
Example #31
0
        /// <summary>
        /// Enqueues the standalone expression for analysis.
        /// </summary>
        void EnqueueExpression(BoundExpression expression, TypeRefContext/*!*/ctx, NamingContext naming)
        {
            Contract.ThrowIfNull(expression);
            Contract.ThrowIfNull(ctx);

            var dummy = new BoundBlock()
            {
                FlowState = new FlowState(new FlowContext(ctx, null)),
                Naming = naming
            };

            dummy.Add(new BoundExpressionStatement(expression));

            _worklist.Enqueue(dummy);
        }
Example #32
0
        private ControlFlowGraph(BoundBlock/*!*/start, BoundBlock/*!*/exit, BoundBlock exception, LabelBlockState[] labels, List<BoundBlock> unreachable)
        {
            Contract.ThrowIfNull(start);
            Contract.ThrowIfNull(exit);

            _start = start;
            _exit = exit;
            //_exception = exception;
            _labels = labels;
            _unrecachable = unreachable ?? new List<BoundBlock>();
        }
 public virtual TResult VisitBlockStatement(Graph.BoundBlock x) => DefaultVisitOperation(x);
Example #34
0
 /// <summary>Visits given block.</summary>
 protected TResult Accept(BoundBlock x) => (x != null) ? x.Accept(this) : default;