private AddressSetView findInstructionFlow(Program program, Address firstAddr,
			AddressSetView clearSet, Stack<Address> todoStarts, TaskMonitor monitor)
			throws CancelledException {

		AddressSet blockSet = new AddressSet();
		Listing listing = program.getListing();
		SymbolTable symbolTable = program.getSymbolTable();

		if (clearOffcut) {
			// Check for initial offcut instruction
			Instruction prevInstr = listing.getInstructionBefore(firstAddr);
			if (prevInstr != null && firstAddr.compareTo(prevInstr.getMaxAddress()) <= 0) {
				clearOffcutFlow(listing.getInstructionAt(firstAddr), todoStarts, monitor);
				return blockSet;
			}
		}

		Hashtable<Address, BlockVertex> vertexMap = new Hashtable<>();

		SimpleBlockModel blockModel = new SimpleBlockModel(program);
		Stack<BlockVertex> todoVertices = new Stack<>();

		Set<Address> destAddrs = new HashSet<>(); // re-usable set for collecting block destination addrs

		// Establish start vertex within flow graph
		CodeBlock startBlock = blockModel.getFirstCodeBlockContaining(firstAddr, monitor);
		blockSet.add(startBlock);
		BlockVertex startVertex = new BlockVertex(startBlock);
		vertexMap.put(startBlock.getMinAddress(), startVertex);
		todoVertices.push(startVertex);

		boolean neverSnipStartBlock = (startAddrs.contains(firstAddr));

		// Follow start block flow and build graph
		while (!todoVertices.isEmpty()) {
			monitor.checkCancelled();
			BlockVertex fromVertex = todoVertices.pop();
			CodeBlock fromBlock = fromVertex.block;
			if (protectedSet.contains(fromBlock.getMinAddress())) {
				continue;
			}
			fromBlock = adjustBlockForSplitProtectedBlock(program, blockModel,
				fromBlock.getFirstStartAddress(), fromBlock);

			// HOT SPOT - getDestinations()
			CodeBlockReferenceIterator blockRefIter = fromBlock.getDestinations(monitor);
			if (clearOffcut) {
				findDestAddrs(fromBlock, destAddrs); // Needed for detecting offcut flows
			}
			while (blockRefIter.hasNext()) {
				monitor.checkCancelled();
				CodeBlockReference cbRef = blockRefIter.next();

				Address blockAddr = cbRef.getReference();
				if (protectedSet.contains(blockAddr)) {
					continue;
				}
				if (clearSet.contains(blockAddr)) {
					continue;
				}
				CodeBlock destBlock = cbRef.getDestinationBlock();
				if (blockAddr.equals(destBlock.getFirstStartAddress())) {
					destBlock = adjustBlockForSplitProtectedBlock(program, blockModel, blockAddr,
						destBlock);
				}
				if (neverSnipStartBlock && destBlock.equals(startBlock)) {
					continue; // do not allow incoming edges to startBlock vertex
				}

				BlockVertex destVertex = vertexMap.get(blockAddr);
				if (destVertex == null) {
					if (listing.getInstructionAt(blockAddr) == null) {
						continue; // do not include data
					}
					Symbol s = symbolTable.getPrimarySymbol(blockAddr);
					if (s != null && s.getSymbolType() == SymbolType.FUNCTION) {
						SourceType source = s.getSource();
						if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
							continue; // keep imported or user-defined function
						}
					}

					if (clearOffcut && !destAddrs.contains(blockAddr)) {
						// Offcut flow was cleared - skip this block
						if (clearOffcutFlow(destBlock, todoStarts, monitor)) {
							continue;
						}
					}
					// TODO: check disassembly hint
					blockSet.add(destBlock);
					destVertex = new BlockVertex(destBlock);
					vertexMap.put(blockAddr, destVertex);
					todoVertices.push(destVertex);
				}
				// HOT SPOT - HashSet.add()
				fromVertex.destVertices.add(destVertex);
				destVertex.srcVertices.add(fromVertex);
			}
		}

		// If start address not start of block, never clear the first part of the block
		if (!firstAddr.equals(startBlock.getMinAddress())) {
			blockSet.deleteRange(startBlock.getMinAddress(), firstAddr.previous());
		}

		ReferenceManager refMgr = program.getReferenceManager();
		FunctionManager functionManager = program.getFunctionManager();
		for (BlockVertex v : vertexMap.values()) {
			monitor.checkCancelled();
			if (v == startVertex || v.srcVertices.isEmpty()) {
				continue;
			}
			Address addr = v.block.getMinAddress();
			Instruction instr = listing.getInstructionAt(addr);
			Address fallFrom = instr.getFallFrom();
			if (fallFrom != null && !blockSet.contains(fallFrom)) {
				prune(v, blockSet);
			}
			else {
				ReferenceIterator refIter = refMgr.getReferencesTo(addr);

				// If there are no references, and there is a defined function inside this block
				//   That starts in this block, with no references to it, then this bad flow couldn't
				//   have created it.
				// TODO: maybe even just symbols with no refs to them should be snipped
				//       code starts at the symbol someone might have disassembled there.
				if (!refIter.hasNext() && functionManager.getFunctionAt(addr) != null) {
					prune(v, blockSet);
					continue;
				}
				while (refIter.hasNext()) {
					monitor.checkCancelled();
					Reference ref = refIter.next();
					Address fromAddr = ref.getFromAddress();
					RefType refType = ref.getReferenceType();
					if (refType.isFlow() && !blockSet.contains(fromAddr) &&
						!clearSet.contains(fromAddr)) {
						prune(v, blockSet);
						break;
					}
					// any addr which corresponds to a entry-point function should be snipped
					if (refType == RefType.EXTERNAL_REF &&
						functionManager.getFunctionAt(addr) != null) {
						prune(v, blockSet);
						break;
					}
				}
			}
		}

		if (repair) {
			clearBadBookmarks(program, blockSet, monitor);
		}

		return blockSet;
	}
Follow code flow and identify address set to be cleared.
If offcut code is encountered, it will be cleared immediately.
@param program
@param firstAddr
@param clearSet code unit areas already decided to clear
@param todoStarts
@param monitor
@return
@throws CancelledException
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearFlowAndRepairCmd.java