Example #1
0
File: CFG.java Project: cwgem/jruby
  private void optimize() {
    // SSS FIXME: Can't we not add some of these exception edges in the first place??
    // Remove exception edges from blocks that couldn't possibly thrown an exception!
    List<Edge> toRemove = new ArrayList<Edge>();
    for (BasicBlock b : graph.allData()) {
      boolean noExceptions = true;
      for (Instr i : b.getInstrs()) {
        if (i.canRaiseException()) {
          noExceptions = false;
          break;
        }
      }

      if (noExceptions) {
        for (Edge<BasicBlock> e : graph.vertexFor(b).getOutgoingEdgesOfType(EdgeType.EXCEPTION)) {
          BasicBlock source = e.getSource().getData();
          BasicBlock destination = e.getDestination().getData();
          toRemove.add(e);

          if (rescuerMap.get(source) == destination) rescuerMap.remove(source);
          if (ensurerMap.get(source) == destination) ensurerMap.remove(source);
        }
      }
    }

    if (!toRemove.isEmpty()) {
      for (Edge edge : toRemove) {
        graph.removeEdge(edge);
      }
    }

    deleteOrphanedBlocks(graph);
  }
Example #2
0
  public BasicBlock cloneForInlining(InlinerInfo ii) {
    BasicBlock clonedBB = ii.getOrCreateRenamedBB(this);
    for (Instr i : getInstrs()) {
      Instr clonedInstr = i.cloneForInlining(ii);
      if (clonedInstr != null) {
        clonedBB.addInstr(clonedInstr);
        if (clonedInstr instanceof YieldInstr)
          ii.recordYieldSite(clonedBB, (YieldInstr) clonedInstr);
      }
    }

    return clonedBB;
  }
Example #3
0
File: CFG.java Project: cwgem/jruby
 void removeBB(BasicBlock b) {
   graph.removeVertexFor(b);
   bbMap.remove(b.getLabel());
   rescuerMap.remove(b);
   ensurerMap.remove(b);
   // SSS FIXME: Patch up rescued regions as well??
 }
Example #4
0
  public void setupYieldArgsAndYieldResult(YieldInstr yi, BasicBlock yieldBB, Arity blockArity) {
    int blockArityValue = blockArity.getValue();
    Operand yieldInstrArg = yi.getYieldArg();

    if ((yieldInstrArg == UndefinedValue.UNDEFINED) || (blockArityValue == 0)) {
      this.yieldArg = new Array(); // Zero-elt array
    } else if (yieldInstrArg instanceof Array) {
      this.yieldArg = yieldInstrArg;
      // 1:1 arg match
      if (((Array) yieldInstrArg).size() == blockArityValue) canMapArgsStatically = true;
    } else {
      // SSS FIXME: The code below is not entirely correct.  We have to process 'yi.getYieldArg()'
      // similar
      // to how InterpretedIRBlockBody (1.8 and 1.9 modes) processes it.  We may need a special
      // instruction
      // that takes care of aligning the stars and bringing good fortune to arg yielder and arg
      // receiver.

      IRScope callerScope = getInlineHostScope();
      boolean needSpecialProcessing = (blockArityValue != -1) && (blockArityValue != 1);
      Variable yieldArgArray = callerScope.getNewTemporaryVariable();
      yieldBB.addInstr(
          new ToAryInstr(yieldArgArray, yieldInstrArg, callerScope.getManager().getTrue()));
      this.yieldArg = yieldArgArray;
    }

    this.yieldResult = yi.getResult();
  }
Example #5
0
 public BasicBlock getOrCreateRenamedBB(BasicBlock bb) {
   BasicBlock renamedBB = getRenamedBB(bb);
   if (renamedBB == null) {
     renamedBB = new BasicBlock(this.callerCFG, getRenamedLabel(bb.getLabel()));
     bbRenameMap.put(bb, renamedBB);
   }
   return renamedBB;
 }
Example #6
0
File: CFG.java Project: cwgem/jruby
  public String toStringInstrs() {
    StringBuilder buf = new StringBuilder();

    for (BasicBlock b : getSortedBasicBlocks()) {
      buf.append(b.toStringInstrs());
    }
    buf.append("\n\n------ Rescue block map ------\n");
    for (BasicBlock bb : rescuerMap.keySet()) {
      buf.append("BB ")
          .append(bb.getID())
          .append(" --> BB ")
          .append(rescuerMap.get(bb).getID())
          .append("\n");
    }
    buf.append("\n\n------ Ensure block map ------\n");
    for (BasicBlock bb : ensurerMap.keySet()) {
      buf.append("BB ")
          .append(bb.getID())
          .append(" --> BB ")
          .append(ensurerMap.get(bb).getID())
          .append("\n");
    }

    List<IRClosure> closures = scope.getClosures();
    if (!closures.isEmpty()) {
      buf.append("\n\n------ Closures encountered in this scope ------\n");
      for (IRClosure c : closures) {
        buf.append(c.toStringBody());
      }
      buf.append("------------------------------------------------\n");
    }

    return buf.toString();
  }
Example #7
0
  public BasicBlock splitAtInstruction(
      Instr splitPoint, Label newLabel, boolean includeSplitPointInstr) {
    BasicBlock newBB = new BasicBlock(_cfg, newLabel);
    int idx = 0;
    int numInstrs = _instrs.size();
    boolean found = false;
    for (Instr i : _instrs) {
      if (i == splitPoint) found = true;

      // Move instructions from split point into the new bb
      if (found) {
        if (includeSplitPointInstr || i != splitPoint) newBB.addInstr(i);
      } else {
        idx++;
      }
    }

    // Remove all instructions from current bb that were moved over.
    for (int j = 0; j < numInstrs - idx; j++) _instrs.remove(idx);

    return newBB;
  }
Example #8
0
  @Override
  public String toString() {
    StringBuilder buf = new StringBuilder("Vertex ");

    buf.append(basicBlock.getID()).append(":\nincoming edges\n");
    for (Edge edge : getIncomingEdges()) {
      buf.append(edge).append("\n");
    }

    buf.append("outgoing edges\n");
    for (Edge edge : getOutgoingEdges()) {
      buf.append(edge).append("\n");
    }

    return buf.toString();
  }
Example #9
0
File: CFG.java Project: cwgem/jruby
  private LinkedList<BasicBlock> buildPostOrderList() {
    LinkedList<BasicBlock> list = new LinkedList<BasicBlock>();
    BasicBlock root = getEntryBB();
    Stack<BasicBlock> stack = new Stack<BasicBlock>();
    stack.push(root);
    BitSet bbSet = new BitSet(1 + getMaxNodeID());
    bbSet.set(root.getID());

    // Non-recursive post-order traversal (the added flag is required to handle cycles and common
    // ancestors)
    while (!stack.empty()) {
      // Check if all children of the top of the stack have been added
      BasicBlock b = stack.peek();
      boolean allChildrenDone = true;
      for (BasicBlock dst : getOutgoingDestinations(b)) {
        int dstID = dst.getID();
        if (!bbSet.get(dstID)) {
          allChildrenDone = false;
          stack.push(dst);
          bbSet.set(dstID);
        }
      }

      // If all children have been added previously, we are ready with 'b' in this round!
      if (allChildrenDone) {
        stack.pop();
        list.add(b);
      }
    }

    // Sanity check!
    for (BasicBlock b : getBasicBlocks()) {
      if (!bbSet.get(b.getID())) {
        printError("BB " + b.getID() + " missing from po list!");
        break;
      }
    }

    return list;
  }
Example #10
0
File: CFG.java Project: cwgem/jruby
  /** Build the Control Flow Graph */
  public DirectedGraph<BasicBlock> build(List<Instr> instrs) {
    // Map of label & basic blocks which are waiting for a bb with that label
    Map<Label, List<BasicBlock>> forwardRefs = new HashMap<Label, List<BasicBlock>>();

    // Map of return address variable and all possible targets (required to connect up ensure blocks
    // with their targets)
    Map<Variable, Set<Label>> retAddrMap = new HashMap<Variable, Set<Label>>();
    Map<Variable, BasicBlock> retAddrTargetMap = new HashMap<Variable, BasicBlock>();

    // List of bbs that have a 'return' instruction
    List<BasicBlock> returnBBs = new ArrayList<BasicBlock>();

    // List of bbs that have a 'throw' instruction
    List<BasicBlock> exceptionBBs = new ArrayList<BasicBlock>();

    // Stack of nested rescue regions
    Stack<ExceptionRegion> nestedExceptionRegions = new Stack<ExceptionRegion>();

    // List of all rescued regions
    List<ExceptionRegion> allExceptionRegions = new ArrayList<ExceptionRegion>();

    // Dummy entry basic block (see note at end to see why)
    entryBB = createBB(nestedExceptionRegions);

    // First real bb
    BasicBlock firstBB = createBB(nestedExceptionRegions);

    // Build the rest!
    BasicBlock currBB = firstBB;
    BasicBlock newBB = null;
    boolean bbEnded = false;
    boolean nextBBIsFallThrough = true;
    for (Instr i : instrs) {
      Operation iop = i.getOperation();
      if (iop == Operation.LABEL) {
        Label l = ((LabelInstr) i).label;
        newBB = createBB(l, nestedExceptionRegions);
        // Jump instruction bbs dont add an edge to the succeeding bb by default
        if (nextBBIsFallThrough) graph.addEdge(currBB, newBB, EdgeType.FALL_THROUGH);
        currBB = newBB;
        bbEnded = false;
        nextBBIsFallThrough = true;

        // Add forward reference edges
        List<BasicBlock> frefs = forwardRefs.get(l);
        if (frefs != null) {
          for (BasicBlock b : frefs) {
            graph.addEdge(b, newBB, EdgeType.REGULAR);
          }
        }
      } else if (bbEnded && (iop != Operation.EXC_REGION_END)) {
        newBB = createBB(nestedExceptionRegions);
        // Jump instruction bbs dont add an edge to the succeeding bb by default
        if (nextBBIsFallThrough)
          graph.addEdge(currBB, newBB, EdgeType.FALL_THROUGH); // currBB cannot be null!
        currBB = newBB;
        bbEnded = false;
        nextBBIsFallThrough = true;
      }

      if (i instanceof ExceptionRegionStartMarkerInstr) {
        // SSS: Do we need this anymore?
        //                currBB.addInstr(i);
        ExceptionRegionStartMarkerInstr ersmi = (ExceptionRegionStartMarkerInstr) i;
        ExceptionRegion rr =
            new ExceptionRegion(ersmi.firstRescueBlockLabel, ersmi.ensureBlockLabel);
        rr.addBB(currBB);
        allExceptionRegions.add(rr);

        if (nestedExceptionRegions.empty()) {
          outermostERs.add(rr);
        } else {
          nestedExceptionRegions.peek().addNestedRegion(rr);
        }

        nestedExceptionRegions.push(rr);
      } else if (i instanceof ExceptionRegionEndMarkerInstr) {
        // SSS: Do we need this anymore?
        //                currBB.addInstr(i);
        nestedExceptionRegions.pop().setEndBB(currBB);
      } else if (iop.endsBasicBlock()) {
        bbEnded = true;
        currBB.addInstr(i);
        Label tgt;
        nextBBIsFallThrough = false;
        if (i instanceof BranchInstr) {
          tgt = ((BranchInstr) i).getJumpTarget();
          nextBBIsFallThrough = true;
        } else if (i instanceof JumpInstr) {
          tgt = ((JumpInstr) i).getJumpTarget();
        } else if (iop.isReturn()) { // BREAK, RETURN, CLOSURE_RETURN
          tgt = null;
          returnBBs.add(currBB);
        } else if (i instanceof ThrowExceptionInstr) {
          tgt = null;
          exceptionBBs.add(currBB);
        } else if (i instanceof JumpIndirectInstr) {
          tgt = null;
          Set<Label> retAddrs = retAddrMap.get(((JumpIndirectInstr) i).getJumpTarget());
          for (Label l : retAddrs) {
            addEdge(currBB, l, forwardRefs);
          }
          // Record the target bb for the retaddr var for any set_addr instrs that appear later and
          // use the same retaddr var
          retAddrTargetMap.put(((JumpIndirectInstr) i).getJumpTarget(), currBB);
        } else {
          throw new RuntimeException(
              "Unhandled case in CFG builder for basic block ending instr: " + i);
        }

        if (tgt != null) addEdge(currBB, tgt, forwardRefs);
      } else if (iop != Operation.LABEL) {
        currBB.addInstr(i);
      }

      if (i instanceof SetReturnAddressInstr) {
        Variable v = i.getResult();
        Label tgtLbl = ((SetReturnAddressInstr) i).getReturnAddr();
        BasicBlock tgtBB = retAddrTargetMap.get(v);
        // If we have the target bb, add the edge
        // If not, record it for fixup later
        if (tgtBB != null) {
          addEdge(tgtBB, tgtLbl, forwardRefs);
        } else {
          Set<Label> addrs = retAddrMap.get(v);
          if (addrs == null) {
            addrs = new HashSet<Label>();
            retAddrMap.put(v, addrs);
          }
          addrs.add(tgtLbl);
        }
      } else if (i instanceof CallInstr) { // Build CFG for the closure if there exists one
        Operand closureArg = ((CallInstr) i).getClosureArg();
        if (closureArg instanceof MetaObject) {
          ((IRClosure) ((MetaObject) closureArg).scope).buildCFG();
        }
      }
    }

    // Process all rescued regions
    for (ExceptionRegion rr : allExceptionRegions) {
      BasicBlock firstRescueBB = bbMap.get(rr.getFirstRescueBlockLabel());

      // 1. Tell the region that firstRescueBB is its protector!
      rr.setFirstRescueBB(firstRescueBB);

      // 2. Record a mapping from the region's exclusive basic blocks to the first bb that will
      // start exception handling for all their exceptions.
      // 3. Add an exception edge from every exclusive bb of the region to firstRescueBB
      BasicBlock ensureBlockBB =
          rr.getEnsureBlockLabel() == null ? null : bbMap.get(rr.getEnsureBlockLabel());
      for (BasicBlock b : rr.getExclusiveBBs()) {
        rescuerMap.put(b, firstRescueBB);
        graph.addEdge(b, firstRescueBB, EdgeType.EXCEPTION);
        if (ensureBlockBB != null) {
          ensurerMap.put(b, ensureBlockBB);
          // SSS FIXME: This is a conservative edge because when a rescue block is present
          // that catches an exception, control never reaches the ensure block directly.
          // Only when we get an error or threadkill even, or when breaks propagate upward
          // do we need to hit an ensure directly.  This edge is present to account for that
          // control-flow scneario.
          graph.addEdge(b, ensureBlockBB, EdgeType.EXCEPTION);
        }
      }
    }

    buildExitBasicBlock(
        nestedExceptionRegions,
        firstBB,
        returnBBs,
        exceptionBBs,
        nextBBIsFallThrough,
        currBB,
        entryBB);

    optimize(); // remove useless cfg edges & orphaned bbs

    return graph;
  }