Example #1
0
  public IRClosure(IRScope lexicalParent, StaticScope staticScope, Arity arity, int argumentType) {
    super(lexicalParent, MetaObject.create(lexicalParent), null, staticScope);
    startLabel = getNewLabel("_CLOSURE_START");
    endLabel = getNewLabel("_CLOSURE_END");
    closureId = lexicalParent.getNextClosureId();
    setName("_CLOSURE_" + closureId);

    this.body = new InterpretedIRBlockBody(this, arity, argumentType);
  }
Example #2
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;
  }