001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.util;
014    
015    import java.util.Enumeration;
016    
017    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
018    
019    /**
020     * SpaceEffGraphNode is a generic graph node. Extend this to implement
021     * specific graph node types.  A node has a list of out edges and a
022     * list of in edges.  We maintain both to support bidirectional traversal
023     * of the graph.
024     */
025    public class SpaceEffGraphNode implements GraphNode {
026    
027      /** scratch field: optimizations use as they wish */
028      public Object scratchObject;
029    
030      /** any optimization can use this for its own purposes */
031      public int scratch;
032    
033      /**
034       * The following word is used for various purposes. The first
035       * 8 bits are used for flags, and the remaining 24 bits for any
036       * node information (node number, for example)
037       */
038      protected int info;
039    
040      static final int DFS_VISITED = 0x01000000;
041      static final int TOP_VISITED = 0x02000000;
042      static final int ON_STACK = 0x04000000;
043    
044      static final int LOOP_HEADER = 0x08000000;
045    
046      static final int INFO_MASK = 0x00ffffff;
047    
048      public final boolean dfsVisited() { return (info & DFS_VISITED) != 0; }
049    
050      public final boolean topVisited() { return (info & TOP_VISITED) != 0; }
051    
052      public final boolean onStack() { return (info & ON_STACK) != 0; }
053    
054      public final boolean flagsOn() { return (info & (DFS_VISITED | TOP_VISITED | ON_STACK)) != 0; }
055    
056      public final boolean isLoopHeader() { return (info & LOOP_HEADER) != 0; }
057    
058      public final void setDfsVisited() { info |= DFS_VISITED; }
059    
060      public final void setTopVisited() { info |= TOP_VISITED; }
061    
062      public final void setOnStack() { info |= ON_STACK; }
063    
064      public final void setDfsVisitedOnStack() { info |= (DFS_VISITED | ON_STACK); }
065    
066      public final void setLoopHeader() { info |= LOOP_HEADER; }
067    
068      public final void clearDfsVisited() { info &= ~DFS_VISITED; }
069    
070      public final void clearTopVisited() { info &= ~TOP_VISITED; }
071    
072      public final void clearOnStack() { info &= ~ON_STACK; }
073    
074      public final void clearFlags() { info &= ~(DFS_VISITED | TOP_VISITED | ON_STACK); }
075    
076      public final void clearLoopHeader() { info &= ~LOOP_HEADER; }
077    
078      @Override
079      public int getScratch() { return scratch; }
080    
081      @Override
082      public int setScratch(int scratch) { return this.scratch = scratch; }
083    
084      public final void setNumber(int value) {
085        info = (info & ~INFO_MASK) | (value & INFO_MASK);
086      }
087    
088      public final int getNumber() {
089        return info & INFO_MASK;
090      }
091    
092      @Override
093      public final int getIndex() {
094        return getNumber();
095      }
096    
097      @Override
098      public final void setIndex(int i) {
099        setNumber(i);
100      }
101    
102      /////////////////
103      // The following is used by several node sorting schemes
104      /////////////////
105    
106      public SpaceEffGraphNode nextSorted;
107    
108      // return the first in/out edge
109    
110      public final SpaceEffGraphEdge firstInEdge() {
111        return _inEdgeStart;
112      }
113    
114      public final SpaceEffGraphEdge firstOutEdge() {
115        return _outEdgeStart;
116      }
117    
118      public final SpaceEffGraphNode firstInNode() {
119        return _inEdgeStart.fromNode();
120      }
121    
122      public final SpaceEffGraphNode firstOutNode() {
123        return _outEdgeStart.toNode();
124      }
125    
126      /**
127       * clear the in set of edges
128       */
129      final void clearIn() {
130        _inEdgeStart = _inEdgeEnd = null;
131      }
132    
133      /**
134       * clear the out set of edges
135       */
136      final void clearOut() {
137        _outEdgeStart = _outEdgeEnd = null;
138      }
139    
140      // deletes all the in/out edges
141    
142      public final void deleteIn() {
143        for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) {
144          e.fromNode().removeOut(e);
145        }
146        clearIn();
147      }
148    
149      public final void deleteOut() {
150        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
151          e.toNode().removeIn(e);
152        }
153        clearOut();
154      }
155    
156      /* get number of in/out edges */
157    
158      public final int getNumberOfIn() {
159        int count = 0;
160        for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) {
161          count++;
162        }
163        return count;
164      }
165    
166      public final int getNumberOfOut() {
167        int count = 0;
168        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
169          count++;
170        }
171        return count;
172      }
173    
174      /* specialized versions */
175      public final boolean hasZeroOut() {
176        return _outEdgeStart == null;
177      }
178    
179      public final boolean hasZeroIn() {
180        return _inEdgeStart == null;
181      }
182    
183      public final boolean hasOneOut() {
184        SpaceEffGraphEdge first = _outEdgeStart;
185        return (first != null) && (first.nextOut == null);
186      }
187    
188      public final boolean hasOneIn() {
189        SpaceEffGraphEdge first = _inEdgeStart;
190        return (first != null) && (first.nextIn == null);
191      }
192    
193      /* returns true if points to the in/out set */
194    
195      public final boolean pointsIn(SpaceEffGraphNode inNode) {
196        for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) {
197          if (e.fromNode() == inNode) return true;
198        }
199        return false;
200      }
201    
202      public final boolean pointsOut(SpaceEffGraphNode outNode) {
203        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
204          if (e.toNode() == outNode) return true;
205        }
206        return false;
207      }
208    
209      public final boolean hasIn(GraphNode in) {
210        return pointsIn((SpaceEffGraphNode) in);
211      }
212    
213      public final boolean hasOut(GraphNode out) {
214        return pointsOut((SpaceEffGraphNode) out);
215      }
216    
217      /*
218       * returns the out edge pointing to node n, if it exists.
219       * returns null otherwise
220       */
221      public final SpaceEffGraphEdge findOutEdgeTo(SpaceEffGraphNode n) {
222        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
223          if (e.toNode() == n) return e;
224        }
225        return null;
226      }
227    
228      /**
229       * replaces the in edge matching e1 with e2.
230       * maintains the ordering of edges<p>
231       *
232       * TODO YUCK: this data structure is messy.  I assume this is in the name
233       * of efficiency, but it makes control flow graph manipulations
234       * a real pain. (SJF)
235       */
236      public final void replaceInEdge(SpaceEffGraphEdge e1, SpaceEffGraphEdge e2) {
237        // set the predecessor of e1 to point to e2
238        if (_inEdgeStart == e1) {
239          _inEdgeStart = e2;
240        } else {
241          // walk the list until we find the predecessor to e1
242          SpaceEffGraphEdge pred = null;
243          for (pred = _inEdgeStart; pred != null; pred = pred.nextIn) {
244            if (pred.nextIn == e1) break;
245          }
246          // if not found, there's an error
247          if (pred == null) {
248            throw new OptimizingCompilerException("SpaceEffGraphNode.replaceInEdge: called incorrectly");
249          }
250          pred.nextIn = e2;
251        }
252        // set e2 to point to e1.nextIn
253        e2.nextIn = e1.nextIn;
254    
255        // fix up _inEdgeStart, _inEdgeEnd
256        if (_inEdgeStart == e1) _inEdgeStart = e2;
257        if (_inEdgeEnd == e1) _inEdgeEnd = e2;
258    
259        // clear the links of e1
260        e1.nextIn = null;
261      }
262    
263      /* returns true if the node is the single predecessor/successor of
264         this block */
265    
266      public final boolean hasOneIn(SpaceEffGraphNode inNode) {
267        SpaceEffGraphEdge first = _inEdgeStart;
268        return (first != null) && (first.nextIn == null) && (first.fromNode() == inNode);
269      }
270    
271      public final boolean hasOneOut(SpaceEffGraphNode outNode) {
272        SpaceEffGraphEdge first = _outEdgeStart;
273        return (first != null) && (first.nextOut == null) && (first.toNode() == outNode);
274      }
275    
276      /* replaces an oldnode with a new node */
277    
278      public final void replaceOut(SpaceEffGraphNode oldOut, SpaceEffGraphNode newOut) {
279        deleteOut(oldOut);
280        insertOut(newOut);
281      }
282    
283      /* inserts an outgoing edge to a node 'to' */
284    
285      public final void insertOut(SpaceEffGraphNode to, SpaceEffGraphEdge e) {
286        this.appendOutEdge(e);
287        to.appendInEdge(e);
288      }
289    
290      /* same as before, if you don't care the edge type */
291    
292      public final void insertOut(SpaceEffGraphNode to) {
293        if (this.pointsOut(to)) return;
294        SpaceEffGraphEdge e = new SpaceEffGraphEdge(this, to);
295        this.appendOutEdge(e);
296        to.appendInEdge(e);
297      }
298    
299      /* delete an outgoing edge to a node */
300    
301      public final void deleteOut(SpaceEffGraphNode node) {
302        SpaceEffGraphEdge edge = this.removeOut(node);
303        node.removeIn(edge);
304      }
305    
306      /* delete an outgoing edge  */
307    
308      public final void deleteOut(SpaceEffGraphEdge e) {
309        SpaceEffGraphNode to = e.toNode();
310        this.removeOut(e);
311        to.removeIn(e);
312      }
313    
314      /* mark nodes in a DFS manner, result written in 'scratch' */
315      /* NOTE: it assummes that the 'dfs' flag has been cleared before */
316    
317      public final void markDFN(int DFN) {
318        setDfsVisited();
319        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
320          SpaceEffGraphNode n = e.toNode();
321          if (!n.dfsVisited()) {
322            n.markDFN(DFN);
323          }
324        }
325        scratch = DFN - 1;
326      }
327    
328      /* mark nodes according to the SCC (Strongly Connected Component Number),
329         result written in 'scratch'
330         NOTE: it assumes that the 'dfs' flag has been cleared before */
331    
332      public final void markSCC(int currSCC) {
333        setDfsVisited();
334        scratch = currSCC;
335        for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) {
336          SpaceEffGraphNode n = e.fromNode();
337          if (!n.dfsVisited()) {
338            n.markSCC(currSCC);
339          }
340        }
341      }
342    
343      /* sort nodes according to DFS. result is a list of nodes with the current
344         as root.  Note: it assumes that the dfs flags have been cleared before */
345    
346      public final void sortDFS() {
347        _sortDFS(null);
348      }
349    
350      protected final void _sortDFS(SpaceEffGraphNode header) {
351        setDfsVisited();
352        for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) {
353          SpaceEffGraphNode n = e.toNode();
354          if (!n.dfsVisited()) {
355            n._sortDFS(header);
356            header = n;
357          }
358        }
359        nextSorted = header;
360      }
361    
362      /* clear all out/in flags */
363    
364      public final void clearOutFlags() {
365        clearFlags();
366        for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) {
367          SpaceEffGraphNode succ = e.toNode();
368          e.clearVisited();
369          if (succ.flagsOn()) {
370            succ.clearOutFlags();
371          }
372        }
373      }
374    
375      public final void clearInFlags() {
376        clearFlags();
377        for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) {
378          SpaceEffGraphNode succ = e.fromNode();
379          e.clearVisited();
380          if (succ.flagsOn()) {
381            succ.clearInFlags();
382          }
383        }
384      }
385    
386      /* topological sort of nodes. result is a list of nodes with the current
387         as root */
388    
389      public final void sortTop() {
390        clearOutFlags();
391        setDfsVisitedOnStack();
392        nextSorted = _sortTop(null);
393      }
394    
395      protected final SpaceEffGraphNode _sortTop(SpaceEffGraphNode tail) {
396        for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) {
397          SpaceEffGraphNode succ = e.toNode();
398          if (!succ.dfsVisited()) {
399            succ.setDfsVisitedOnStack();
400            tail = succ._sortTop(tail);
401          } else if (succ.onStack() || succ == this) {
402            e.setVisited(); // back edge
403          }
404        }
405        clearOnStack();
406        for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) {
407          SpaceEffGraphNode succ = e.toNode();
408          if (!succ.topVisited() && !e.visited()) {
409            succ.nextSorted = tail;
410            tail = succ;
411            succ.setTopVisited();
412          }
413        }
414        return tail;
415      }
416    
417      /* reverse topological sort of nodes. result is a list of nodes with the
418         current as root */
419    
420      public final void sortRevTop() {
421        clearInFlags();
422        setDfsVisitedOnStack();
423        nextSorted = _sortRevTop(null);
424      }
425    
426      protected final SpaceEffGraphNode _sortRevTop(SpaceEffGraphNode tail) {
427        for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) {
428          SpaceEffGraphNode succ = e.fromNode();
429          if (!succ.dfsVisited()) {
430            succ.setDfsVisitedOnStack();
431            tail = succ._sortRevTop(tail);
432          } else if (succ.onStack() || succ == this) {
433            e.setVisited(); // forward edge
434          }
435        }
436        clearOnStack();
437        for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) {
438          SpaceEffGraphNode succ = e.fromNode();
439          if (!succ.topVisited() && !e.visited()) {
440            succ.nextSorted = tail;
441            tail = succ;
442            succ.setTopVisited();
443          }
444        }
445        return tail;
446      }
447    
448      /* print sorted nodes starting from this */
449    
450      final void printSorted() {
451        for (SpaceEffGraphNode n = this; n != null; n = n.nextSorted) {
452          System.out.println(n);
453        }
454      }
455    
456      /**
457       * Revert the sequence of out edges
458       */
459      final void revertOuts() {
460        SpaceEffGraphEdge last = null;
461        SpaceEffGraphEdge e = firstOutEdge();
462        _outEdgeStart = _outEdgeEnd;
463        _outEdgeEnd = e;
464        while (e != null) {
465          SpaceEffGraphEdge next = e.getNextOut();
466          e.appendOut(last);
467          last = e;
468          e = next;
469        }
470      }
471    
472      /* enumerations to get the nodes/edges */
473    
474      public interface GraphEdgeEnumeration<T extends GraphEdge> extends Enumeration<T> {
475        // Same as nextElement but avoid the need to downcast from Object
476        T next();
477      }
478    
479      public final InEdgeEnumeration inEdges() {
480        return new InEdgeEnumeration(this);
481      }
482    
483      public final OutEdgeEnumeration outEdges() {
484        return new OutEdgeEnumeration(this);
485      }
486    
487      @Override
488      public final Enumeration<GraphNode> inNodes() {
489        return new InNodeEnumeration(this);
490      }
491    
492      @Override
493      public final Enumeration<GraphNode> outNodes() {
494        return new OutNodeEnumeration(this);
495      }
496    
497      /* print utilities */
498    
499      public void printInEdges() {
500        for (SpaceEffGraphEdge in = firstInEdge(); in != null; in = in.getNextIn()) {
501          System.out.println(in.fromNodeString());
502        }
503      }
504    
505      public void printOutEdges() {
506        for (SpaceEffGraphEdge out = firstOutEdge(); out != null; out = out.getNextOut()) {
507          System.out.println(out.toNodeString());
508        }
509      }
510    
511      public void printInNodes() {
512        for (SpaceEffGraphEdge in = firstInEdge(); in != null; in = in.getNextIn()) {
513          System.out.println(in.fromNode());
514        }
515      }
516    
517      public void printOutNodes() {
518        for (SpaceEffGraphEdge out = firstOutEdge(); out != null; out = out.getNextOut()) {
519          System.out.println(out.toNode());
520        }
521      }
522    
523      public void printExtended() {
524        System.out.println(this);
525      }
526    
527      /////////////////
528      // Implementation: the following is not intended for general client use
529      /////////////////
530    
531      protected SpaceEffGraphEdge _outEdgeStart;
532      protected SpaceEffGraphEdge _outEdgeEnd;
533      protected SpaceEffGraphEdge _inEdgeStart;
534      protected SpaceEffGraphEdge _inEdgeEnd;
535    
536      //
537      // add an in/out edge from 'node' to this node.
538      //
539    
540      // (SJF): I had to make these public to do SSA transformations.
541      // TODO: The CFG data structure should not depend this tightly
542      // on the underlying Graph implementation, but rather should be
543      // designed so that the SSA-like transformations are easy to do.
544    
545      protected final void appendInEdge(SpaceEffGraphEdge e) {
546        SpaceEffGraphEdge inEdgeEnd = _inEdgeEnd;
547        if (inEdgeEnd != null) {
548          inEdgeEnd.appendIn(e);
549        } else {
550          _inEdgeStart = e;
551        }
552        _inEdgeEnd = e;
553      }
554    
555      protected final void appendOutEdge(SpaceEffGraphEdge e) {
556        SpaceEffGraphEdge outEdgeEnd = _outEdgeEnd;
557        if (outEdgeEnd != null) {
558          outEdgeEnd.appendOut(e);
559        } else {
560          _outEdgeStart = e;
561        }
562        _outEdgeEnd = e;
563      }
564    
565      /* remove and edge/node from the in/out set */
566    
567      protected final void removeIn(SpaceEffGraphEdge InEdge) {
568        SpaceEffGraphEdge prev = null;
569        for (SpaceEffGraphEdge edge = _inEdgeStart; edge != null; prev = edge, edge = edge.nextIn) {
570          if (edge == InEdge) {
571            SpaceEffGraphEdge next = edge.nextIn;
572            if (prev == null) {
573              _inEdgeStart = next;
574            } else {
575              prev.appendIn(next);
576            }
577            if (next == null) {
578              _inEdgeEnd = prev;
579            }
580            break;
581          }
582        }
583      }
584    
585      protected final SpaceEffGraphEdge removeIn(SpaceEffGraphNode InNode) {
586        SpaceEffGraphEdge edge, prev = null;
587        for (edge = _inEdgeStart; edge != null; prev = edge, edge = edge.nextIn) {
588          if (edge.fromNode() == InNode) {
589            SpaceEffGraphEdge next = edge.nextIn;
590            if (prev == null) {
591              _inEdgeStart = next;
592            } else {
593              prev.appendIn(next);
594            }
595            if (next == null) {
596              _inEdgeEnd = prev;
597            }
598            break;
599          }
600        }
601        return edge;
602      }
603    
604      protected final void removeOut(SpaceEffGraphEdge OutEdge) {
605        SpaceEffGraphEdge edge, prev = null;
606        for (edge = _outEdgeStart; edge != null; prev = edge, edge = edge.nextOut) {
607          if (edge == OutEdge) {
608            SpaceEffGraphEdge next = edge.nextOut;
609            if (prev == null) {
610              _outEdgeStart = next;
611            } else {
612              prev.appendOut(next);
613            }
614            if (next == null) {
615              _outEdgeEnd = prev;
616            }
617            break;
618          }
619        }
620      }
621    
622      protected final SpaceEffGraphEdge removeOut(SpaceEffGraphNode OutNode) {
623        SpaceEffGraphEdge edge, prev = null;
624        for (edge = _outEdgeStart; edge != null; prev = edge, edge = edge.nextOut) {
625          if (edge.toNode() == OutNode) {
626            SpaceEffGraphEdge next = edge.nextOut;
627            if (prev == null) {
628              _outEdgeStart = next;
629            } else {
630              prev.appendOut(next);
631            }
632            if (next == null) {
633              _outEdgeEnd = prev;
634            }
635            break;
636          }
637        }
638        return edge;
639      }
640    
641      static final class InEdgeEnumeration implements GraphEdgeEnumeration<GraphEdge> {
642        private SpaceEffGraphEdge _edge;
643    
644        public InEdgeEnumeration(SpaceEffGraphNode n) {
645          _edge = n._inEdgeStart;
646        }
647    
648        @Override
649        public boolean hasMoreElements() { return _edge != null; }
650    
651        @Override
652        public SpaceEffGraphEdge nextElement() { return next(); }
653    
654        @Override
655        public SpaceEffGraphEdge next() {
656          SpaceEffGraphEdge e = _edge;
657          _edge = e.nextIn;
658          return e;
659        }
660      }
661    
662      static final class InNodeEnumeration implements Enumeration<GraphNode> {
663        private SpaceEffGraphEdge _edge;
664    
665        public InNodeEnumeration(SpaceEffGraphNode n) {
666          _edge = n._inEdgeStart;
667        }
668    
669        @Override
670        public boolean hasMoreElements() { return _edge != null; }
671    
672        @Override
673        public GraphNode nextElement() {
674          SpaceEffGraphEdge e = _edge;
675          _edge = e.nextIn;
676          return e.fromNode();
677        }
678      }
679    
680      public static final class OutEdgeEnumeration implements GraphEdgeEnumeration<GraphEdge> {
681        private SpaceEffGraphEdge _edge;
682    
683        public OutEdgeEnumeration(SpaceEffGraphNode n) {
684          _edge = n._outEdgeStart;
685        }
686    
687        @Override
688        public boolean hasMoreElements() { return _edge != null; }
689    
690        @Override
691        public GraphEdge nextElement() { return next(); }
692    
693        @Override
694        public GraphEdge next() {
695          SpaceEffGraphEdge e = _edge;
696          _edge = e.nextOut;
697          return e;
698        }
699      }
700    
701      static final class OutNodeEnumeration implements Enumeration<GraphNode> {
702        private SpaceEffGraphEdge _edge;
703    
704        public OutNodeEnumeration(SpaceEffGraphNode n) {
705          _edge = n._outEdgeStart;
706        }
707    
708        @Override
709        public boolean hasMoreElements() { return _edge != null; }
710    
711        @Override
712        public GraphNode nextElement() {
713          SpaceEffGraphEdge e = _edge;
714          _edge = e.nextOut;
715          return e.toNode();
716        }
717      }
718    
719      /**
720       * Links inlined from DoublyLinkedListElement.
721       */
722      public SpaceEffGraphNode prev, next;
723    
724      /**
725       * Get the next node.
726       * @return next node
727       */
728      public final SpaceEffGraphNode getNext() {
729        return next;
730      }
731    
732      /**
733       * Get the previous node.
734       * @return previous node
735       */
736      public final SpaceEffGraphNode getPrev() {
737        return prev;
738      }
739    
740      /**
741       * Append a given node after this node.
742       * @param n the node to append
743       */
744      public final void append(SpaceEffGraphNode n) {
745        next = n;
746        n.prev = this;
747      }
748    
749      /**
750       * Remove this node from the list.
751       * @return the next node in the list
752       */
753      public final SpaceEffGraphNode remove() {
754        // copy old links
755        SpaceEffGraphNode Prev = prev, Next = next;
756    
757        // reset old links
758        prev = null;
759        next = null;
760    
761        // compute new links
762        if (Prev != null) Prev.next = Next;
763        if (Next != null) Next.prev = Prev;
764    
765        // return next node
766        return Next;
767      }
768    }
769    
770