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); } } } } }
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; }
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); } } } } }
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); }
public RegionMaker(MethodNode mth) { this.mth = mth; if (Consts.DEBUG) { this.processedBlocks = new BitSet(mth.getBasicBlocks().size()); } }
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; }