private static @NotNull Pair<Sdk, JavaSdkVersion> getRuntimeSdk(@NotNull Project project, int oldestPossibleVersion, Function<Set<? extends Sdk>, Pair<Sdk, JavaSdkVersion>> fallbackSdkProvider) {
    final Map<Sdk, Integer> candidates = new HashMap<>();
    Consumer<Sdk> addSdk = sdk -> {
      if (sdk != null && sdk.getSdkType() instanceof JavaSdkType) {
        final Integer count = candidates.putIfAbsent(sdk, 1);
        if (count != null) {
          candidates.put(sdk, count + 1);
        }
      }
    };

    addSdk.accept(ProjectRootManager.getInstance(project).getProjectSdk());
    for (Module module : ModuleManager.getInstance(project).getModules()) {
      addSdk.accept(ModuleRootManager.getInstance(module).getSdk());
    }

    final CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project);
    if (configuration.getJavacCompiler().equals(configuration.getDefaultCompiler()) && JavacConfiguration.getOptions(project, JavacConfiguration.class).PREFER_TARGET_JDK_COMPILER) {
      // for javac, if compiler from associated SDK instead of cross-compilation is preferred, use a different policy:
      // select the most frequently used jdk from the sdks that are associated with the project, but not older than <oldestPossibleVersion>
      // this policy attempts to compile as many modules as possible without spawning a separate javac process

      final List<Pair<Sdk, JavaSdkVersion>> sortedSdks = EntryStream.of(candidates)
        .reverseSorted(Map.Entry.comparingByValue())
        .keys()
        .mapToEntry(sdk -> JavaVersion.tryParse(sdk.getVersionString()))
        .filterValues(version -> version != null && version.isAtLeast(oldestPossibleVersion))
        .mapValues(JavaSdkVersion::fromJavaVersion)
        .nonNullValues()
        .mapKeyValue(Pair::create)
        .toList();

      if (!sortedSdks.isEmpty()) {
        // first, try to find the most used JDK of version 9+ => JRT FS support will be needed
        final Pair<Sdk, JavaSdkVersion> sdk9_plus = ContainerUtil.find(sortedSdks, p -> p.second.isAtLeast(JavaSdkVersion.JDK_1_9));
        return sdk9_plus != null? sdk9_plus : sortedSdks.iterator().next(); // get the most used
      }
    }

    // now select the latest version from the sdks that are used in the project, but not older than <oldestPossibleVersion>
    return StreamEx.ofKeys(candidates)
      .mapToEntry(sdk -> JavaVersion.tryParse(sdk.getVersionString()))
      .filterValues(version -> version != null && version.isAtLeast(oldestPossibleVersion))
      .max(Map.Entry.comparingByValue())
      .map(p -> Pair.create(p.getKey(), JavaSdkVersion.fromJavaVersion(p.getValue())))
      .filter(p -> p.second != null)
      .orElseGet(() -> fallbackSdkProvider.apply(candidates.keySet()));
  }
private static @NotNull Pair<Sdk, JavaSdkVersion> getRuntimeSdk(@NotNull Project project, int oldestPossibleVersion, Function<Set<? extends Sdk>, Pair<Sdk, JavaSdkVersion>> fallbackSdkProvider)