1 /*
2  * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package com.sun.hotspot.igv.servercompiler;
26 
27 import com.sun.hotspot.igv.data.InputBlock;
28 import com.sun.hotspot.igv.data.InputEdge;
29 import com.sun.hotspot.igv.data.InputGraph;
30 import com.sun.hotspot.igv.data.InputNode;
31 import com.sun.hotspot.igv.data.services.Scheduler;
32 import java.util.*;
33 
34 /**
35  *
36  * @author Thomas Wuerthinger
37  */
38 public class ServerCompilerScheduler implements Scheduler {
39 
40     private static class Node {
41 
42         public InputNode inputNode;
43         public Set<Node> succs = new HashSet<>();
44         public List<Node> preds = new ArrayList<>();
45         public InputBlock block;
46         public boolean isBlockProjection;
47         public boolean isBlockStart;
48     }
49     private InputGraph graph;
50     private Collection<Node> nodes;
51     private Map<InputNode, Node> inputNodeToNode;
52     private Vector<InputBlock> blocks;
53     private Map<InputBlock, InputBlock> dominatorMap;
54     private Map<InputBlock, Integer> blockIndex;
55     private InputBlock[][] commonDominator;
56     private static final Comparator<InputEdge> edgeComparator = new Comparator<InputEdge>() {
57 
58         @Override
59         public int compare(InputEdge o1, InputEdge o2) {
60             return o1.getToIndex() - o2.getToIndex();
61         }
62     };
63 
buildBlocks()64     public void buildBlocks() {
65 
66         blocks = new Vector<>();
67         Node root = findRoot();
68         if (root == null) {
69             return;
70         }
71         Stack<Node> stack = new Stack<>();
72         Set<Node> visited = new HashSet<>();
73         stack.add(root);
74         int blockCount = 0;
75         InputBlock rootBlock = null;
76 
77 
78         while (!stack.isEmpty()) {
79             Node proj = stack.pop();
80             Node parent = proj;
81             if (proj.isBlockProjection && proj.preds.size() > 0) {
82                 parent = proj.preds.get(0);
83             }
84 
85             if (!visited.contains(parent)) {
86                 visited.add(parent);
87                 InputBlock block = graph.addBlock(Integer.toString(blockCount));
88                 blocks.add(block);
89                 if (parent == root) {
90                     rootBlock = block;
91                 }
92                 blockCount++;
93                 parent.block = block;
94                 if (proj != parent && proj.succs.size() == 1 && proj.succs.contains(root)) {
95                     // Special treatment of Halt-nodes
96                     proj.block = block;
97                 }
98 
99                 Node p = proj;
100                 do {
101                     if (p.preds.size() == 0 || p.preds.get(0) == null) {
102                         p = parent;
103                         break;
104                     }
105 
106                     p = p.preds.get(0);
107                     if (p == proj) {
108                         // Cycle, stop
109                         break;
110                     }
111 
112                     if (p.block == null) {
113                         p.block = block;
114                     }
115                 } while (!p.isBlockProjection && !p.isBlockStart);
116 
117                 if (block != rootBlock) {
118                     for (Node n : p.preds) {
119                         if (n != null && n != p) {
120                             if (n.isBlockProjection) {
121                                 n = n.preds.get(0);
122                             }
123                             if (n.block != null) {
124                                 graph.addBlockEdge(n.block, block);
125                             }
126                         }
127                     }
128                 }
129 
130                 for (Node n : parent.succs) {
131                     if (n != root && n.isBlockProjection) {
132                         for (Node n2 : n.succs) {
133 
134                             if (n2 != parent && n2.block != null && n2.block != rootBlock) {
135                                 graph.addBlockEdge(block, n2.block);
136                             }
137                         }
138                     } else {
139                         if (n != parent && n.block != null && n.block != rootBlock) {
140                             graph.addBlockEdge(block, n.block);
141                         }
142                     }
143                 }
144 
145                 int num_preds = p.preds.size();
146                 int bottom = -1;
147                 if (isRegion(p) || isPhi(p)) {
148                     bottom = 0;
149                 }
150 
151                 int pushed = 0;
152                 for (int i = num_preds - 1; i > bottom; i--) {
153                     if (p.preds.get(i) != null && p.preds.get(i) != p) {
154                         stack.push(p.preds.get(i));
155                         pushed++;
156                     }
157                 }
158 
159                 if (pushed == 0 && p == root) {
160                     // TODO: special handling when root backedges are not built yet
161                 }
162             }
163         }
164 
165         for (Node n : nodes) {
166             InputBlock block = n.block;
167             if (block != null) {
168                 block.addNode(n.inputNode.getId());
169             }
170         }
171 
172         int z = 0;
173         blockIndex = new HashMap<>(blocks.size());
174         for (InputBlock b : blocks) {
175             blockIndex.put(b, z);
176             z++;
177         }
178     }
179 
getBlockName(InputNode n)180     private String getBlockName(InputNode n) {
181         return n.getProperties().get("block");
182     }
183 
184     @Override
schedule(InputGraph graph)185     public Collection<InputBlock> schedule(InputGraph graph) {
186         if (graph.getNodes().isEmpty()) {
187             return Collections.emptyList();
188         }
189 
190         if (graph.getBlocks().size() > 0) {
191             Collection<InputNode> tmpNodes = new ArrayList<>(graph.getNodes());
192             for (InputNode n : tmpNodes) {
193                 String block = getBlockName(n);
194                 if (graph.getBlock(n) == null) {
195                     graph.getBlock(block).addNode(n.getId());
196                     assert graph.getBlock(n) != null;
197                 }
198             }
199             return graph.getBlocks();
200         } else {
201             nodes = new ArrayList<>();
202             inputNodeToNode = new HashMap<>(graph.getNodes().size());
203 
204             this.graph = graph;
205             buildUpGraph();
206             buildBlocks();
207             buildDominators();
208             buildCommonDominators();
209             scheduleLatest();
210 
211             InputBlock noBlock = null;
212             for (InputNode n : graph.getNodes()) {
213                 if (graph.getBlock(n) == null) {
214                     if (noBlock == null) {
215                         noBlock = graph.addBlock("(no block)");
216                         blocks.add(noBlock);
217                     }
218 
219                     graph.setBlock(n, noBlock);
220                 }
221                 assert graph.getBlock(n) != null;
222             }
223 
224             return blocks;
225         }
226     }
227 
scheduleLatest()228     private void scheduleLatest() {
229         Node root = findRoot();
230         if(root == null) {
231             assert false : "No root found!";
232             return;
233         }
234 
235         // Mark all nodes reachable in backward traversal from root
236         Set<Node> reachable = new HashSet<>();
237         reachable.add(root);
238         Stack<Node> stack = new Stack<>();
239         stack.push(root);
240         while (!stack.isEmpty()) {
241             Node cur = stack.pop();
242             for (Node n : cur.preds) {
243                 if (!reachable.contains(n)) {
244                     reachable.add(n);
245                     stack.push(n);
246                 }
247             }
248         }
249 
250         Set<Node> unscheduled = new HashSet<>();
251         for (Node n : this.nodes) {
252             if (n.block == null && reachable.contains(n)) {
253                 unscheduled.add(n);
254             }
255         }
256 
257         while (unscheduled.size() > 0) {
258             boolean progress = false;
259 
260             Set<Node> newUnscheduled = new HashSet<>();
261             for (Node n : unscheduled) {
262 
263                 InputBlock block = null;
264                 if (this.isPhi(n) && n.preds.get(0) != null) {
265                     // Phi nodes in same block as region nodes
266                     block = n.preds.get(0).block;
267                 } else {
268                     for (Node s : n.succs) {
269                         if (reachable.contains(s)) {
270                             if (s.block == null) {
271                                 block = null;
272                                 break;
273                             } else {
274                                 if (block == null) {
275                                     block = s.block;
276                                 } else {
277                                     block = commonDominator[this.blockIndex.get(block)][blockIndex.get(s.block)];
278                                 }
279                             }
280                         }
281                     }
282                 }
283 
284                 if (block != null) {
285                     n.block = block;
286                     block.addNode(n.inputNode.getId());
287                     progress = true;
288                 } else {
289                     newUnscheduled.add(n);
290                 }
291             }
292 
293             unscheduled = newUnscheduled;
294 
295             if (!progress) {
296                 break;
297             }
298         }
299 
300         Set<Node> curReachable = new HashSet<>(reachable);
301         for (Node n : curReachable) {
302             if (n.block != null) {
303                 for (Node s : n.succs) {
304                     if (!reachable.contains(s)) {
305                         markWithBlock(s, n.block, reachable);
306                     }
307                 }
308             }
309         }
310 
311     }
312 
markWithBlock(Node n, InputBlock b, Set<Node> reachable)313     private void markWithBlock(Node n, InputBlock b, Set<Node> reachable) {
314         assert !reachable.contains(n);
315         Stack<Node> stack = new Stack<>();
316         stack.push(n);
317         n.block = b;
318         b.addNode(n.inputNode.getId());
319         reachable.add(n);
320 
321         while (!stack.isEmpty()) {
322             Node cur = stack.pop();
323             for (Node s : cur.succs) {
324                 if (!reachable.contains(s)) {
325                     reachable.add(s);
326                     s.block = b;
327                     b.addNode(s.inputNode.getId());
328                     stack.push(s);
329                 }
330             }
331 
332             for (Node s : cur.preds) {
333                 if (!reachable.contains(s)) {
334                     reachable.add(s);
335                     s.block = b;
336                     b.addNode(s.inputNode.getId());
337                     stack.push(s);
338                 }
339             }
340         }
341     }
342 
343     private class BlockIntermediate {
344 
345         InputBlock block;
346         int index;
347         int dominator;
348         int semi;
349         int parent;
350         int label;
351         int ancestor;
352         List<Integer> pred;
353         List<Integer> bucket;
354     }
355 
buildCommonDominators()356     public void buildCommonDominators() {
357         commonDominator = new InputBlock[this.blocks.size()][this.blocks.size()];
358         for (int i = 0; i < blocks.size(); i++) {
359             for (int j = 0; j < blocks.size(); j++) {
360                 commonDominator[i][j] = getCommonDominator(i, j);
361             }
362         }
363     }
364 
getCommonDominator(int a, int b)365     public InputBlock getCommonDominator(int a, int b) {
366         InputBlock ba = blocks.get(a);
367         InputBlock bb = blocks.get(b);
368         if (ba == bb) {
369             return ba;
370         }
371         Set<InputBlock> visited = new HashSet<>();
372         while (ba != null) {
373             visited.add(ba);
374             ba = dominatorMap.get(ba);
375         }
376 
377         while (bb != null) {
378             if (visited.contains(bb)) {
379                 return bb;
380             }
381             bb = dominatorMap.get(bb);
382         }
383 
384         assert false;
385         return null;
386     }
387 
buildDominators()388     public void buildDominators() {
389         dominatorMap = new HashMap<>(graph.getBlocks().size());
390         if (blocks.size() == 0) {
391             return;
392         }
393         Vector<BlockIntermediate> intermediate = new Vector<>(graph.getBlocks().size());
394         Map<InputBlock, BlockIntermediate> map = new HashMap<>(graph.getBlocks().size());
395         int z = 0;
396         for (InputBlock b : blocks) {
397             BlockIntermediate bi = new BlockIntermediate();
398             bi.block = b;
399             bi.index = z;
400             bi.dominator = -1;
401             bi.semi = -1;
402             bi.parent = -1;
403             bi.label = z;
404             bi.ancestor = -1;
405             bi.pred = new ArrayList<>();
406             bi.bucket = new ArrayList<>();
407             intermediate.add(bi);
408             map.put(b, bi);
409             z++;
410         }
411         Stack<Integer> stack = new Stack<>();
412         stack.add(0);
413 
414         Vector<BlockIntermediate> array = new Vector<>();
415         intermediate.get(0).dominator = 0;
416 
417         int n = 0;
418         while (!stack.isEmpty()) {
419             int index = stack.pop();
420             BlockIntermediate ib = intermediate.get(index);
421             ib.semi = n;
422             array.add(ib);
423             n = n + 1;
424             for (InputBlock b : ib.block.getSuccessors()) {
425                 BlockIntermediate succ = map.get(b);
426                 if (succ.semi == -1) {
427                     succ.parent = index;
428                     stack.push(succ.index); // TODO: check if same node could be pushed twice
429                 }
430                 succ.pred.add(index);
431             }
432         }
433 
434         for (int i = n - 1; i > 0; i--) {
435             BlockIntermediate block = array.get(i);
436             int block_index = block.index;
437             for (int predIndex : block.pred) {
438                 int curIndex = eval(predIndex, intermediate);
439                 BlockIntermediate curBlock = intermediate.get(curIndex);
440                 if (curBlock.semi < block.semi) {
441                     block.semi = curBlock.semi;
442                 }
443             }
444 
445 
446             int semiIndex = block.semi;
447             BlockIntermediate semiBlock = array.get(semiIndex);
448             semiBlock.bucket.add(block_index);
449 
450             link(block.parent, block_index, intermediate);
451             BlockIntermediate parentBlock = intermediate.get(block.parent);
452 
453             for (int j = 0; j < parentBlock.bucket.size(); j++) {
454                 for (int curIndex : parentBlock.bucket) {
455                     int newIndex = eval(curIndex, intermediate);
456                     BlockIntermediate curBlock = intermediate.get(curIndex);
457                     BlockIntermediate newBlock = intermediate.get(newIndex);
458                     int dom = block.parent;
459                     if (newBlock.semi < curBlock.semi) {
460                         dom = newIndex;
461                     }
462 
463                     curBlock.dominator = dom;
464                 }
465             }
466 
467 
468             parentBlock.bucket.clear();
469         }
470 
471         for (int i = 1; i < n; i++) {
472 
473             BlockIntermediate block = array.get(i);
474             int block_index = block.index;
475 
476             int semi_index = block.semi;
477             BlockIntermediate semi_block = array.get(semi_index);
478 
479             if (block.dominator != semi_block.index) {
480                 int new_dom = intermediate.get(block.dominator).dominator;
481                 block.dominator = new_dom;
482             }
483         }
484 
485         for (BlockIntermediate ib : intermediate) {
486             if (ib.dominator == -1) {
487                 ib.dominator = 0;
488             }
489         }
490 
491         for (BlockIntermediate bi : intermediate) {
492             InputBlock b = bi.block;
493             int dominator = bi.dominator;
494             InputBlock dominatorBlock = null;
495             if (dominator != -1) {
496                 dominatorBlock = intermediate.get(dominator).block;
497             }
498 
499             if (dominatorBlock == b) {
500                 dominatorBlock = null;
501             }
502             this.dominatorMap.put(b, dominatorBlock);
503         }
504     }
505 
compress(int index, Vector<BlockIntermediate> blocks)506     private void compress(int index, Vector<BlockIntermediate> blocks) {
507         BlockIntermediate block = blocks.get(index);
508 
509         int ancestor = block.ancestor;
510         assert ancestor != -1;
511 
512         BlockIntermediate ancestor_block = blocks.get(ancestor);
513         if (ancestor_block.ancestor != -1) {
514             compress(ancestor, blocks);
515 
516             int label = block.label;
517             BlockIntermediate label_block = blocks.get(label);
518 
519             int ancestor_label = ancestor_block.label;
520             BlockIntermediate ancestor_label_block = blocks.get(label);
521             if (ancestor_label_block.semi < label_block.semi) {
522                 block.label = ancestor_label;
523             }
524 
525             block.ancestor = ancestor_block.ancestor;
526         }
527     }
528 
eval(int index, Vector<BlockIntermediate> blocks)529     private int eval(int index, Vector<BlockIntermediate> blocks) {
530         BlockIntermediate block = blocks.get(index);
531         if (block.ancestor == -1) {
532             return index;
533         } else {
534             compress(index, blocks);
535             return block.label;
536         }
537     }
538 
link(int index1, int index2, Vector<BlockIntermediate> blocks)539     private void link(int index1, int index2, Vector<BlockIntermediate> blocks) {
540         BlockIntermediate block2 = blocks.get(index2);
541         block2.ancestor = index1;
542     }
543 
isRegion(Node n)544     private boolean isRegion(Node n) {
545         return n.inputNode.getProperties().get("name").equals("Region");
546     }
547 
isPhi(Node n)548     private boolean isPhi(Node n) {
549         return n.inputNode.getProperties().get("name").equals("Phi");
550     }
551 
findRoot()552     private Node findRoot() {
553         Node minNode = null;
554         Node alternativeRoot = null;
555 
556         for (Node node : nodes) {
557             InputNode inputNode = node.inputNode;
558             String s = inputNode.getProperties().get("name");
559             if (s != null && s.equals("Root")) {
560                 return node;
561             }
562 
563             if (alternativeRoot == null && node.preds.isEmpty()) {
564                 alternativeRoot = node;
565             }
566 
567             if (minNode == null || node.inputNode.getId() < minNode.inputNode.getId()) {
568                 minNode = node;
569             }
570         }
571 
572         if (alternativeRoot != null) {
573             return alternativeRoot;
574         } else {
575             return minNode;
576         }
577     }
578 
buildUpGraph()579     public void buildUpGraph() {
580 
581         for (InputNode n : graph.getNodes()) {
582             Node node = new Node();
583             node.inputNode = n;
584             nodes.add(node);
585             String p = n.getProperties().get("is_block_proj");
586             node.isBlockProjection = (p != null && p.equals("true"));
587             p = n.getProperties().get("is_block_start");
588             node.isBlockStart = (p != null && p.equals("true"));
589             inputNodeToNode.put(n, node);
590         }
591 
592         Map<Integer, List<InputEdge>> edgeMap = new HashMap<>(graph.getEdges().size());
593         for (InputEdge e : graph.getEdges()) {
594 
595             int to = e.getTo();
596             if (!edgeMap.containsKey(to)) {
597                 edgeMap.put(to, new ArrayList<InputEdge>());
598             }
599 
600 
601             List<InputEdge> list = edgeMap.get(to);
602             list.add(e);
603         }
604 
605 
606         for (Integer i : edgeMap.keySet()) {
607 
608             List<InputEdge> list = edgeMap.get(i);
609             Collections.sort(list, edgeComparator);
610 
611             int to = i;
612             InputNode toInputNode = graph.getNode(to);
613             Node toNode = inputNodeToNode.get(toInputNode);
614             for (InputEdge e : list) {
615                 assert to == e.getTo();
616                 int from = e.getFrom();
617                 InputNode fromInputNode = graph.getNode(from);
618                 Node fromNode = inputNodeToNode.get(fromInputNode);
619                 fromNode.succs.add(toNode);
620                 toNode.preds.add(fromNode);
621             }
622         }
623     }
624 }
625