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 */
25package com.sun.hotspot.igv.servercompiler;
26
27import com.sun.hotspot.igv.data.InputBlock;
28import com.sun.hotspot.igv.data.InputEdge;
29import com.sun.hotspot.igv.data.InputGraph;
30import com.sun.hotspot.igv.data.InputNode;
31import com.sun.hotspot.igv.data.services.Scheduler;
32import java.util.*;
33
34/**
35 *
36 * @author Thomas Wuerthinger
37 */
38public 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
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
180    private String getBlockName(InputNode n) {
181        return n.getProperties().get("block");
182    }
183
184    @Override
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
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
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
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
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
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
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
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
539    private void link(int index1, int index2, Vector<BlockIntermediate> blocks) {
540        BlockIntermediate block2 = blocks.get(index2);
541        block2.ancestor = index1;
542    }
543
544    private boolean isRegion(Node n) {
545        return n.inputNode.getProperties().get("name").equals("Region");
546    }
547
548    private boolean isPhi(Node n) {
549        return n.inputNode.getProperties().get("name").equals("Phi");
550    }
551
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
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