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