[dart2js] Add a flag to dump unused dill libraries.

Change-Id: I27c3fd8121c2744212afab70a827d515e45666ae
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220062
Commit-Queue: Joshua Litt <joshualitt@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Joshua Litt 2021-12-04 20:34:15 +00:00 committed by Commit Bot
parent 0b73860956
commit 3bfb2db3d0
6 changed files with 41 additions and 0 deletions

View file

@ -82,6 +82,9 @@ enum OutputType {
/// Deferred map output.
deferredMap,
/// Unused libraries output.
dumpUnusedLibraries,
/// Implementation specific output used for debugging the compiler.
debug,
}

View file

@ -175,6 +175,9 @@ class Flags {
// For backward compatibility the option is still accepted, but it is ignored.
static const String initializingFormalAccess = '--initializing-formal-access';
// Whether or not to dump a list of unused libraries.
static const String dumpUnusedLibraries = '--dump-unused-libraries';
// Experimental flags.
static const String resolveOnly = '--resolve-only';

View file

@ -5,6 +5,7 @@
library dart2js.compiler_base;
import 'dart:async' show Future;
import 'dart:convert' show jsonEncode;
import 'package:front_end/src/api_unstable/dart2js.dart'
show clearStringTokenCanonicalizer;
@ -246,6 +247,31 @@ abstract class Compiler {
return options.readClosedWorldUri != null && options.readDataUri != null;
}
/// Dumps a list of unused [ir.Library]'s in the [KernelResult]. This *must*
/// be called before [setMainAndTrimComponent], because that method will
/// discard the unused [ir.Library]s.
void dumpUnusedLibraries(KernelResult result) {
var usedUris = result.libraries.toSet();
bool isUnused(ir.Library l) => !usedUris.contains(l.importUri);
String libraryString(ir.Library library) {
return '${library.importUri}(${library.fileUri})';
}
var unusedLibraries =
result.component.libraries.where(isUnused).map(libraryString).toList();
unusedLibraries.sort();
var jsonLibraries = jsonEncode(unusedLibraries);
outputProvider.createOutputSink(options.outputUri.pathSegments.last,
'unused.json', api.OutputType.dumpUnusedLibraries)
..add(jsonLibraries)
..close();
reporter.reportInfo(
reporter.createMessage(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
'text': "${unusedLibraries.length} unused libraries out of "
"${result.component.libraries.length}. Dumping to JSON."
}));
}
Future runInternal() async {
clearState();
var compilationTarget = options.compilationTarget;
@ -324,6 +350,9 @@ abstract class Compiler {
// deserialized modular data because some of this data may reference
// 'trimmed' elements.
if (options.fromDill) {
if (options.dumpUnusedLibraries) {
dumpUnusedLibraries(result);
}
if (options.entryUri != null) {
result.setMainAndTrimComponent(options.entryUri);
}

View file

@ -627,6 +627,7 @@ Future<api.CompilationResult> compile(List<String> argv,
OptionHandler(Flags.benchmarkingExperiment, passThrough),
OptionHandler(Flags.soundNullSafety, setNullSafetyMode),
OptionHandler(Flags.noSoundNullSafety, setNullSafetyMode),
OptionHandler(Flags.dumpUnusedLibraries, passThrough),
// TODO(floitsch): remove conditional directives flag.
// We don't provide the info-message yet, since we haven't publicly

View file

@ -564,6 +564,9 @@ class CompilerOptions implements DiagnosticOptions {
/// Verbosity level used for filtering messages during compilation.
fe.Verbosity verbosity = fe.Verbosity.all;
// Whether or not to dump a list of unused libraries.
bool dumpUnusedLibraries = false;
late FeatureOptions features;
// -------------------------------------------------
@ -690,6 +693,7 @@ class CompilerOptions implements DiagnosticOptions {
.._noSoundNullSafety = _hasOption(options, Flags.noSoundNullSafety)
.._mergeFragmentsThreshold =
_extractIntOption(options, '${Flags.mergeFragmentsThreshold}=')
..dumpUnusedLibraries = _hasOption(options, Flags.dumpUnusedLibraries)
..cfeInvocationModes = fe.InvocationMode.parseArguments(
_extractStringOption(options, '${Flags.cfeInvocationModes}=', '')!,
onError: onError)

View file

@ -351,6 +351,7 @@ class RandomAccessFileOutputProvider implements CompilerOutput {
uri = out.resolve('$name.$extension');
break;
case OutputType.dumpInfo:
case OutputType.dumpUnusedLibraries:
case OutputType.deferredMap:
if (name == '') {
name = out.pathSegments.last;