@Nonnull
	public CompilerResult compile(@Nonnull JavacArguments arguments,
	                              @Nullable Workspace workspace,
	                              @Nullable List<WorkspaceResource> supplementaryResources,
	                              @Nullable JavacListener listener) {
		if (compiler == null)
			return new CompilerResult(new IllegalStateException("Cannot load 'javac' compiler."));

		String className = arguments.getClassName();

		// Class input map
		VirtualUnitMap unitMap = new VirtualUnitMap();
		unitMap.addSource(className, arguments.getClassSource());

		// Create a file manager to track files in-memory rather than on-disk
		List<WorkspaceResource> virtualClassPath = workspace == null ?
				Collections.emptyList() : workspace.getAllResources(true);
		if (supplementaryResources != null)
			virtualClassPath = Lists.combine(virtualClassPath, supplementaryResources);

		// Generate phantom classes if the workspace does not already have phantoms in it.
		if (workspace != null && config.getGeneratePhantoms().getValue()
				&& workspace.getSupportingResources().stream().noneMatch(resource -> resource instanceof GeneratedPhantomWorkspaceResource)) {
			// Only scan the target class and any of its inner classes for content to fill in.
			List<JvmClassInfo> classesToScan = workspace.findJvmClasses(c -> c.getName().equals(className) || c.isInnerClassOf(className)).stream()
					.map(p -> p.getValue().asJvmClass())
					.collect(Collectors.toList());
			if (!classesToScan.isEmpty()) {
				try {
					WorkspaceResource phantomResource = phantomGenerator.createPhantomsForClasses(workspace, classesToScan);
					int generatedCount = phantomResource.getJvmClassBundle().size();
					if (generatedCount > 0)
						logger.debug("Generated {} phantoms for pre-compile", generatedCount);
					virtualClassPath = Lists.add(virtualClassPath, phantomResource);
				} catch (PhantomGenerationException ex) {
					logger.warn("Failed to generate phantoms for compilation against '{}'", className, ex);
				}
			}
		}

		List<CompilerDiagnostic> diagnostics = new ArrayList<>();
		JavacListener listenerWrapper = createRecordingListener(listener, diagnostics);
		JavaFileManager fmFallback = compiler.getStandardFileManager(listenerWrapper, Locale.getDefault(), UTF_8);
		JavaFileManager fm = new VirtualFileManager(unitMap, virtualClassPath, fmFallback);

		// Populate arguments
		List<String> args = new ArrayList<>();

		// Classpath
		String cp = arguments.getClassPath();
		if (cp != null) {
			args.add("-classpath");
			args.add(cp);
			logger.debugging(l -> l.info("Compiler classpath: {}", cp));
		}

		// Target version
		int target = arguments.getVersionTarget();
		args.add("--release");
		args.add(Integer.toString(target));
		logger.debugging(l -> l.info("Compiler target: {}", target));

		// Debug info
		String debugArg = arguments.createDebugValue();
		args.add(debugArg);
		logger.debugging(l -> l.info("Compiler debug: {}", debugArg));

		// Invoke compiler
		try {
			JavaCompiler.CompilationTask task =
					compiler.getTask(null, fm, listenerWrapper, args, null, unitMap.getFiles());
			if (task.call()) {
				logger.debugging(l -> l.info("Compilation of '{}' finished", className));
			} else {
				logger.debugging(l -> l.error("Compilation of '{}' failed", className));
			}
			CompileMap compilations = unitMap.getCompilations();
			int downsampleTarget = arguments.getDownsampleTarget();
			if (downsampleTarget >= MIN_DOWNSAMPLE_VER)
				compilations.downsample(downsampleTarget);
			else if (downsampleTarget >= 0)
				logger.warn("Cannot downsample beyond Java {}", JavacCompiler.MIN_DOWNSAMPLE_VER);
			return new CompilerResult(compilations, diagnostics);
		} catch (RuntimeException ex) {
			logger.debugging(l -> l.error("Compilation of '{}' crashed", className, ex));
			return new CompilerResult(ex);
		}
	}
@param arguments
		Wrapper of all arguments.
@param workspace
		Optional workspace to include for additional classpath support.
@param supplementaryResources
		Optional resources to further extend the compilation classpath with.
@param listener
		Optional listener to handle feedback with,
		mirroring what is reported by {@link CompilerResult#getDiagnostics()}

@return Compilation result wrapper.
recaf-core/src/main/java/software/coley/recaf/services/compile/JavacCompiler.java