@Nullable private static CaseGroupTree getForbiddenCaseGroupPredecessor(CFG.Block predecessor, Map<CFG.Block, CaseGroupTree> cfgBlockToCaseGroupMap, Set<CFG.Block> seen) { if (cfgBlockToCaseGroupMap.get(predecessor) != null) { return cfgBlockToCaseGroupMap.get(predecessor); } if (seen.contains(predecessor)) { return null; } seen.add(predecessor); return predecessor.predecessors().stream() .map(previousPredecessors -> getForbiddenCaseGroupPredecessor(previousPredecessors, cfgBlockToCaseGroupMap, seen)) .filter(Objects::nonNull) .findFirst() .orElse(null); }
@Nullable private static CaseGroupTree getForbiddenCaseGroupPredecessor(CFG.Block predecessor, Map<CFG.Block, CaseGroupTree> cfgBlockToCaseGroupMap, Set<CFG.Block> seen) { if (cfgBlockToCaseGroupMap.get(predecessor) != null) { return cfgBlockToCaseGroupMap.get(predecessor); } if (seen.contains(predecessor)) { return null; } seen.add(predecessor); return predecessor.predecessors().stream() .map(previousPredecessors -> getForbiddenCaseGroupPredecessor(previousPredecessors, cfgBlockToCaseGroupMap, seen)) .filter(Objects::nonNull) .findFirst() .orElse(null); }
private static Stream<CaseGroupTree> getForbiddenCaseGroupPredecessors(CFG.Block cfgBlock, Map<CFG.Block, CaseGroupTree> cfgBlockToCaseGroupMap) { CaseGroupTree caseGroup = cfgBlockToCaseGroupMap.get(cfgBlock); return cfgBlock.predecessors().stream() .map(predecessor -> getForbiddenCaseGroupPredecessor(predecessor, cfgBlockToCaseGroupMap, new HashSet<>())) .filter(Objects::nonNull) .filter(predecessor -> !intentionalFallThrough(predecessor, caseGroup)) .distinct(); }
private void analyzeCFG(Map<CFG.Block, Set<Symbol>> in, Map<CFG.Block, Set<Symbol>> kill, Map<CFG.Block, Set<Symbol>> gen) { Deque<CFG.Block> workList = new LinkedList<>(); workList.addAll(cfg.reversedBlocks()); while (!workList.isEmpty()) { CFG.Block block = workList.removeFirst(); Set<Symbol> blockOut = out.get(block); if (blockOut == null) { blockOut = new HashSet<>(); out.put(block, blockOut); } for (CFG.Block successor : block.successors()) { Set<Symbol> inOfSuccessor = in.get(successor); if (inOfSuccessor != null) { blockOut.addAll(inOfSuccessor); } } // in = gen and (out - kill) Set<Symbol> newIn = new HashSet<>(gen.get(block)); newIn.addAll(Sets.difference(blockOut, kill.get(block))); if (newIn.equals(in.get(block))) { continue; } in.put(block, newIn); for (CFG.Block predecessor : block.predecessors()) { workList.addLast(predecessor); } } }
private static boolean hasPredecessorInBlock(CFG.Block block, Tree loop) { for (CFG.Block predecessor : block.predecessors()) { List<Tree> predecessorElements = predecessor.elements(); if (predecessorElements.isEmpty()) { return hasPredecessorInBlock(predecessor, loop); } else { Tree predecessorFirstElement = predecessorElements.get(0); if (isForStatementInitializer(predecessorFirstElement, loop)) { // skip 'for' loops initializers continue; } if (isForStatementUpdate(predecessorFirstElement, loop)) { // there is no way to reach the 'for' loop update return !predecessor.predecessors().isEmpty(); } if (isDescendant(predecessorFirstElement, loop)) { return true; } } } return false; }
private static boolean hasPredecessorInBlock(CFG.Block block, Tree loop) { for (CFG.Block predecessor : block.predecessors()) { List<Tree> predecessorElements = predecessor.elements(); if (predecessorElements.isEmpty()) { return hasPredecessorInBlock(predecessor, loop); } else { Tree predecessorFirstElement = predecessorElements.get(0); if (isForStatementInitializer(predecessorFirstElement, loop)) { // skip 'for' loops initializers continue; } if (isForStatementUpdate(predecessorFirstElement, loop)) { // there is no way to reach the 'for' loop update return !predecessor.predecessors().isEmpty(); } if (isDescendant(predecessorFirstElement, loop)) { return true; } } } return false; }
private void analyzeCFG(Map<CFG.Block, Set<Symbol>> in, Map<CFG.Block, Set<Symbol>> kill, Map<CFG.Block, Set<Symbol>> gen) { Deque<CFG.Block> workList = new LinkedList<>(); workList.addAll(cfg.reversedBlocks()); while (!workList.isEmpty()) { CFG.Block block = workList.removeFirst(); Set<Symbol> blockOut = out.computeIfAbsent(block, k -> new HashSet<>()); block.successors().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); block.exceptions().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); // in = gen and (out - kill) Set<Symbol> newIn = new HashSet<>(gen.get(block)); newIn.addAll(Sets.difference(blockOut, kill.get(block))); if (newIn.equals(in.get(block))) { continue; } in.put(block, newIn); block.predecessors().forEach(workList::addLast); } }
private void analyzeCFG(Map<CFG.Block, Set<Symbol>> in, Map<CFG.Block, Set<Symbol>> kill, Map<CFG.Block, Set<Symbol>> gen) { Deque<CFG.Block> workList = new LinkedList<>(); workList.addAll(cfg.reversedBlocks()); while (!workList.isEmpty()) { CFG.Block block = workList.removeFirst(); Set<Symbol> blockOut = out.computeIfAbsent(block, k -> new HashSet<>()); block.successors().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); block.exceptions().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); // in = gen and (out - kill) Set<Symbol> newIn = new HashSet<>(gen.get(block)); newIn.addAll(Sets.difference(blockOut, kill.get(block))); if (newIn.equals(in.get(block))) { continue; } in.put(block, newIn); block.predecessors().forEach(workList::addLast); } }
private static Stream<CaseGroupTree> getForbiddenCaseGroupPredecessors(CFG.Block cfgBlock, Map<CFG.Block, CaseGroupTree> cfgBlockToCaseGroupMap) { CaseGroupTree caseGroup = cfgBlockToCaseGroupMap.get(cfgBlock); return cfgBlock.predecessors().stream() .map(predecessor -> getForbiddenCaseGroupPredecessor(predecessor, cfgBlockToCaseGroupMap, new HashSet<>())) .filter(Objects::nonNull) .filter(predecessor -> !intentionalFallThrough(predecessor, caseGroup)) .distinct(); }