private @Nullable Map<FinishElementInstruction, BitSet> findLiveVars() {
    final Map<FinishElementInstruction, BitSet> result = new HashMap<>();

    boolean ok = runDfa(false, (instruction, liveVars) -> {
      if (instruction instanceof FinishElementInstruction) {
        BitSet set = result.get(instruction);
        if (set != null) {
          set.or(liveVars);
          return (BitSet)set.clone();
        }
        else if (!liveVars.isEmpty()) {
          result.put((FinishElementInstruction)instruction, (BitSet)liveVars.clone());
        }
      }

      List<DfaVariableValue> writtenVariables = instruction.getWrittenVariables(myFactory);
      if (!writtenVariables.isEmpty()) {
        BitSet newVars = (BitSet)liveVars.clone();
        for (DfaVariableValue written : writtenVariables) {
          newVars.clear(written.getID());
          for (DfaVariableValue var : written.getDependentVariables()) {
            newVars.clear(var.getID());
          }
        }
        return newVars;
      } else {
        var processor = new Consumer<DfaVariableValue>() {
          boolean cloned = false;
          BitSet newVars = liveVars;

          @Override
          public void accept(DfaVariableValue value) {
            if (!newVars.get(value.getID())) {
              if (!cloned) {
                newVars = (BitSet)newVars.clone();
                cloned = true;
              }
              newVars.set(value.getID());
            }
          }
        };
        StreamEx.of(instruction.getRequiredVariables(myFactory))
          .flatMap(v -> StreamEx.of(v.getDependentVariables()).prepend(v)).distinct().forEach(processor);
        return processor.newVars;
      }
    });
    return ok ? result : null;
  }
private @Nullable Map<FinishElementInstruction, BitSet> findLiveVars()