예제 #1
0
  private static void placePhi(MethodNode mth, int regNum, LiveVarAnalysis la) {
    List<BlockNode> blocks = mth.getBasicBlocks();
    int blocksCount = blocks.size();
    BitSet hasPhi = new BitSet(blocksCount);
    BitSet processed = new BitSet(blocksCount);
    Deque<BlockNode> workList = new LinkedList<BlockNode>();

    BitSet assignBlocks = la.getAssignBlocks(regNum);
    for (int id = assignBlocks.nextSetBit(0); id >= 0; id = assignBlocks.nextSetBit(id + 1)) {
      processed.set(id);
      workList.add(blocks.get(id));
    }
    while (!workList.isEmpty()) {
      BlockNode block = workList.pop();
      BitSet domFrontier = block.getDomFrontier();
      for (int id = domFrontier.nextSetBit(0); id >= 0; id = domFrontier.nextSetBit(id + 1)) {
        if (!hasPhi.get(id) && la.isLive(id, regNum)) {
          BlockNode df = blocks.get(id);
          addPhi(df, regNum);
          hasPhi.set(id);
          if (!processed.get(id)) {
            processed.set(id);
            workList.add(df);
          }
        }
      }
    }
  }
예제 #2
0
 private static boolean removePhiList(MethodNode mth, List<PhiInsn> insnToRemove) {
   if (insnToRemove.isEmpty()) {
     return false;
   }
   for (BlockNode block : mth.getBasicBlocks()) {
     PhiListAttr phiList = block.get(AType.PHI_LIST);
     if (phiList == null) {
       continue;
     }
     List<PhiInsn> list = phiList.getList();
     for (PhiInsn phiInsn : insnToRemove) {
       if (list.remove(phiInsn)) {
         for (InsnArg arg : phiInsn.getArguments()) {
           SSAVar sVar = ((RegisterArg) arg).getSVar();
           if (sVar != null) {
             sVar.setUsedInPhi(null);
           }
         }
         InstructionRemover.remove(mth, block, phiInsn);
       }
     }
     if (list.isEmpty()) {
       block.remove(AType.PHI_LIST);
     }
   }
   insnToRemove.clear();
   return true;
 }
예제 #3
0
 private static void fixLastTryCatchAssign(MethodNode mth) {
   for (BlockNode block : mth.getBasicBlocks()) {
     PhiListAttr phiList = block.get(AType.PHI_LIST);
     if (phiList == null || !block.contains(AType.EXC_HANDLER)) {
       continue;
     }
     for (PhiInsn phi : phiList.getList()) {
       for (int i = 0; i < phi.getArgsCount(); i++) {
         RegisterArg arg = phi.getArg(i);
         InsnNode parentInsn = arg.getAssignInsn();
         if (parentInsn != null
             && parentInsn.getResult() != null
             && parentInsn.contains(AFlag.TRY_LEAVE)) {
           phi.removeArg(arg);
         }
       }
     }
   }
 }
예제 #4
0
 private static boolean removeUselessPhi(MethodNode mth) {
   List<PhiInsn> insnToRemove = new ArrayList<PhiInsn>();
   for (SSAVar var : mth.getSVars()) {
     // phi result not used
     if (var.getUseCount() == 0) {
       InsnNode assignInsn = var.getAssign().getParentInsn();
       if (assignInsn != null && assignInsn.getType() == InsnType.PHI) {
         insnToRemove.add((PhiInsn) assignInsn);
       }
     }
   }
   for (BlockNode block : mth.getBasicBlocks()) {
     PhiListAttr phiList = block.get(AType.PHI_LIST);
     if (phiList == null) {
       continue;
     }
     for (PhiInsn phi : phiList.getList()) {
       removePhiWithSameArgs(phi, insnToRemove);
     }
   }
   return removePhiList(mth, insnToRemove);
 }
예제 #5
0
 public RegionMaker(MethodNode mth) {
   this.mth = mth;
   if (Consts.DEBUG) {
     this.processedBlocks = new BitSet(mth.getBasicBlocks().size());
   }
 }
예제 #6
0
  private BlockNode processSwitch(
      IRegion currentRegion, BlockNode block, SwitchNode insn, RegionStack stack) {
    SwitchRegion sw = new SwitchRegion(currentRegion, block);
    currentRegion.getSubBlocks().add(sw);

    int len = insn.getTargets().length;
    // sort by target
    Map<Integer, List<Object>> casesMap = new LinkedHashMap<Integer, List<Object>>(len);
    for (int i = 0; i < len; i++) {
      Object key = insn.getKeys()[i];
      int targ = insn.getTargets()[i];
      List<Object> keys = casesMap.get(targ);
      if (keys == null) {
        keys = new ArrayList<Object>(2);
        casesMap.put(targ, keys);
      }
      keys.add(key);
    }

    Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<BlockNode, List<Object>>(len);
    for (Map.Entry<Integer, List<Object>> entry : casesMap.entrySet()) {
      BlockNode c = getBlockByOffset(entry.getKey(), block.getSuccessors());
      assert c != null;
      blocksMap.put(c, entry.getValue());
    }
    BlockNode defCase = getBlockByOffset(insn.getDefaultCaseOffset(), block.getSuccessors());
    if (defCase != null) {
      blocksMap.remove(defCase);
    }
    LoopInfo loop = mth.getLoopForBlock(block);

    Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<BlockNode, BlockNode>();

    List<BlockNode> basicBlocks = mth.getBasicBlocks();
    BitSet outs = new BitSet(basicBlocks.size());
    outs.or(block.getDomFrontier());
    for (BlockNode s : block.getCleanSuccessors()) {
      BitSet df = s.getDomFrontier();
      // fall through case block
      if (df.cardinality() > 1) {
        if (df.cardinality() > 2) {
          LOG.debug("Unexpected case pattern, block: {}, mth: {}", s, mth);
        } else {
          BlockNode first = basicBlocks.get(df.nextSetBit(0));
          BlockNode second = basicBlocks.get(df.nextSetBit(first.getId() + 1));
          if (second.getDomFrontier().get(first.getId())) {
            fallThroughCases.put(s, second);
            df = new BitSet(df.size());
            df.set(first.getId());
          } else if (first.getDomFrontier().get(second.getId())) {
            fallThroughCases.put(s, first);
            df = new BitSet(df.size());
            df.set(second.getId());
          }
        }
      }
      outs.or(df);
    }
    outs.clear(block.getId());
    if (loop != null) {
      outs.clear(loop.getStart().getId());
    }

    stack.push(sw);
    stack.addExits(BlockUtils.bitSetToBlocks(mth, outs));

    // check cases order if fall through case exists
    if (!fallThroughCases.isEmpty()) {
      if (isBadCasesOrder(blocksMap, fallThroughCases)) {
        LOG.debug("Fixing incorrect switch cases order, method: {}", mth);
        blocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
        if (isBadCasesOrder(blocksMap, fallThroughCases)) {
          LOG.error("Can't fix incorrect switch cases order, method: {}", mth);
          mth.add(AFlag.INCONSISTENT_CODE);
        }
      }
    }

    // filter 'out' block
    if (outs.cardinality() > 1) {
      // remove exception handlers
      BlockUtils.cleanBitSet(mth, outs);
    }
    if (outs.cardinality() > 1) {
      // filter loop start and successors of other blocks
      for (int i = outs.nextSetBit(0); i >= 0; i = outs.nextSetBit(i + 1)) {
        BlockNode b = basicBlocks.get(i);
        outs.andNot(b.getDomFrontier());
        if (b.contains(AFlag.LOOP_START)) {
          outs.clear(b.getId());
        } else {
          for (BlockNode s : b.getCleanSuccessors()) {
            outs.clear(s.getId());
          }
        }
      }
    }

    if (loop != null && outs.cardinality() > 1) {
      outs.clear(loop.getEnd().getId());
    }
    if (outs.cardinality() == 0) {
      // one or several case blocks are empty,
      // run expensive algorithm for find 'out' block
      for (BlockNode maybeOut : block.getSuccessors()) {
        boolean allReached = true;
        for (BlockNode s : block.getSuccessors()) {
          if (!isPathExists(s, maybeOut)) {
            allReached = false;
            break;
          }
        }
        if (allReached) {
          outs.set(maybeOut.getId());
          break;
        }
      }
    }
    BlockNode out = null;
    if (outs.cardinality() == 1) {
      out = basicBlocks.get(outs.nextSetBit(0));
      stack.addExit(out);
    } else if (loop == null && outs.cardinality() > 1) {
      LOG.warn("Can't detect out node for switch block: {} in {}", block, mth);
    }
    if (loop != null) {
      // check if 'continue' must be inserted
      BlockNode end = loop.getEnd();
      if (out != end && out != null) {
        insertContinueInSwitch(block, out, end);
      }
    }

    if (!stack.containsExit(defCase)) {
      sw.setDefaultCase(makeRegion(defCase, stack));
    }
    for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
      BlockNode caseBlock = entry.getKey();
      if (stack.containsExit(caseBlock)) {
        // empty case block
        sw.addCase(entry.getValue(), new Region(stack.peekRegion()));
      } else {
        BlockNode next = fallThroughCases.get(caseBlock);
        stack.addExit(next);
        Region caseRegion = makeRegion(caseBlock, stack);
        stack.removeExit(next);
        if (next != null) {
          next.add(AFlag.FALL_THROUGH);
          caseRegion.add(AFlag.FALL_THROUGH);
        }
        sw.addCase(entry.getValue(), caseRegion);
        // 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
      }
    }

    stack.pop();
    return out;
  }