public AddressSet flowConstants(Address startAddr, AddressSetView restrictSet,
			ContextEvaluator eval, boolean saveContext, TaskMonitor monitor)
			throws CancelledException {

		this.evaluator = eval;

		initValidAddressSpaces();

		// if assuming, make a copy of programContext
		savedProgramContext = programContext;
		savedSpaceContext = spaceContext;
		if (!saveContext) {
			context = saveOffCurrentContext(startAddr);
		}

		context.flowToAddress(Address.NO_ADDRESS, startAddr);
		
		// copy any current registers with values into the context
		Register[] regWithVals = program.getProgramContext().getRegistersWithValues();
		for (Register regWithVal : regWithVals) {
			RegisterValue regVal =
				program.getProgramContext().getRegisterValue(regWithVal, startAddr);
			if (regVal == null) {
				continue;
			}
			if (!regVal.hasValue()) {
				continue;
			}

			Register reg = regVal.getRegister();
			context.putValue(context.getRegisterVarnode(reg), context.createConstantVarnode(
				regVal.getUnsignedValue().longValue(), reg.getMinimumByteSize()), false);
		}
		context.propogateResults(false);

		AddressSet bodyDone = null;
		try {
			bodyDone = flowConstants(startAddr, restrictSet, eval, context, monitor);
		}
		finally {
			programContext = savedProgramContext;
			spaceContext = savedSpaceContext;
		}

		readExecutableAddress = context.readExecutableCode();

		return bodyDone;
	}
Process a subroutine using the processor function.
The process function can control what flows are followed and when to stop.

@param startAddr start address
@param restrictSet the address set to restrict the constant flow to
@param eval the context evaluator to use
@param saveContext true if the context should be saved
@param monitor the task monitor
@return the address set of instructions that were followed
@throws CancelledException if the task is cancelled
Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java