Record (StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) { Map<BasicBlock, Boolean> mapLast = new HashMap<>(); BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead(); BasicBlock firstBasicBlock = firstBlockStatement.getBlock(); Instruction instrFirst = firstBasicBlock.getInstruction(0); int firstCode = switch (instrFirst.opcode) { case CodeConstants.opc_pop -> 1; case CodeConstants.opc_astore -> 2; default -> 0; }; ExprProcessor proc = new ExprProcessor(methodDescriptor, varProcessor); proc.processStatement(root, cl); SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); ssa.splitVariables(root, mt); List<Exprent> expressions = firstBlockStatement.getExprents(); VarVersionPair pair = new VarVersionPair((VarExprent)((AssignmentExprent)expressions.get(firstCode == 2 ? 1 : 0)).getLeft()); FlattenStatementsHelper flattenHelper = new FlattenStatementsHelper(); DirectGraph dgraph = flattenHelper.buildDirectGraph(root); LinkedList<DirectNode> stack = new LinkedList<>(); stack.add(dgraph.first); Set<DirectNode> setVisited = new HashSet<>(); while (!stack.isEmpty()) { DirectNode node = stack.removeFirst(); if (setVisited.contains(node)) { continue; } setVisited.add(node); BasicBlockStatement blockStatement = null; if (node.block != null) { blockStatement = node.block; } else if (node.predecessors.size() == 1) { blockStatement = node.predecessors.get(0).block; } boolean isTrueExit = true; if (firstCode != 1) { isTrueExit = false; for (int i = 0; i < node.exprents.size(); i++) { Exprent exprent = node.exprents.get(i); if (firstCode == 0) { List<Exprent> lst = exprent.getAllExprents(); lst.add(exprent); boolean found = false; for (Exprent expr : lst) { if (expr.type == Exprent.EXPRENT_VAR && new VarVersionPair((VarExprent)expr).equals(pair)) { found = true; break; } } if (found) { found = false; if (exprent.type == Exprent.EXPRENT_EXIT) { ExitExprent exit = (ExitExprent)exprent; if (exit.getExitType() == ExitExprent.EXIT_THROW && exit.getValue().type == Exprent.EXPRENT_VAR) { found = true; } } if (!found) { return null; } else { isTrueExit = true; } } } else { // firstCode == 2 // searching for a load instruction if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { AssignmentExprent assignment = (AssignmentExprent)exprent; if (assignment.getRight().type == Exprent.EXPRENT_VAR && new VarVersionPair((VarExprent)assignment.getRight()).equals(pair)) { Exprent next = null; if (i == node.exprents.size() - 1) { if (node.successors.size() == 1) { DirectNode nd = node.successors.get(0); if (!nd.exprents.isEmpty()) { next = nd.exprents.get(0); } } } else { next = node.exprents.get(i + 1); } boolean found = false; if (next != null && next.type == Exprent.EXPRENT_EXIT) { ExitExprent exit = (ExitExprent)next; if (exit.getExitType() == ExitExprent.EXIT_THROW && exit.getValue().type == Exprent.EXPRENT_VAR && assignment.getLeft().equals(exit.getValue())) { found = true; } } if (!found) { return null; } else { isTrueExit = true; } } } } } } // find finally exits if (blockStatement != null && blockStatement.getBlock() != null) { Statement handler = fstat.getHandler(); for (StatEdge edge : blockStatement.getSuccessorEdges(EdgeType.DIRECT_ALL)) { if (edge.getType() != EdgeType.REGULAR && handler.containsStatement(blockStatement) && !handler.containsStatement(edge.getDestination())) { Boolean existingFlag = mapLast.get(blockStatement.getBlock()); // note: the dummy node is also processed! if (existingFlag == null || !existingFlag) { mapLast.put(blockStatement.getBlock(), isTrueExit); break; } } } } stack.addAll(node.successors); } // an empty `finally` block? if (fstat.getHandler().type == StatementType.BASIC_BLOCK) { boolean isFirstLast = mapLast.containsKey(firstBasicBlock); InstructionSequence seq = firstBasicBlock.getSeq(); boolean isEmpty = switch (firstCode) { case 0 -> isFirstLast && seq.length() == 1; case 1 -> seq.length() == 1; case 2 -> isFirstLast ? seq.length() == 3 : seq.length() == 1; default -> false; }; if (isEmpty) { firstCode = 3; } } return new Record(firstCode, mapLast); }