[dart2js] Add a 'modular analysis' phase.
Change-Id: Idda666911a15e1726a15db65eb0cce2733851fdc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237633
Reviewed-by: Mark Zhou <markzipan@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 918c9fa..7abb1f8 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -50,6 +50,7 @@
import 'null_compiler_output.dart' show NullCompilerOutput;
import 'options.dart' show CompilerOptions;
import 'phase/load_kernel.dart' as load_kernel;
+import 'phase/modular_analysis.dart' as modular_analysis;
import 'serialization/task.dart';
import 'serialization/serialization.dart';
import 'serialization/strategies.dart';
@@ -322,7 +323,11 @@
programSplitConstraintsData = constraintParser.read(programSplitJson);
}
- if (onlyPerformGlobalTypeInference) {
+ if (options.cfeOnly) {
+ await runLoadKernel();
+ } else if (options.modularMode) {
+ await runModularAnalysis();
+ } else if (onlyPerformGlobalTypeInference) {
ir.Component component =
await serializationTask.deserializeComponentAndUpdateOptions();
var closedWorldAndIndices =
@@ -357,48 +362,25 @@
await generateJavaScriptCode(globalTypeInferenceResults,
indices: closedWorldAndIndices.indices);
} else {
- final input = load_kernel.Input(options, provider, reporter,
- initializedCompilerState, forceSerializationForTesting);
- load_kernel.Output output =
- await loadKernelTask.measure(() async => load_kernel.run(input));
+ load_kernel.Output output = await runLoadKernel();
if (output == null || compilationFailed) return;
- reporter.log("Kernel load complete");
- if (retainDataForTesting) {
- componentForTesting = output.component;
- }
ir.Component component = output.component;
List<Uri> libraries = output.libraries;
frontendStrategy.registerLoadedLibraries(component, libraries);
-
- if (options.modularMode) {
- await runModularAnalysis(component, output.moduleLibraries);
- } else {
- List<ModuleData> data;
- if (options.hasModularAnalysisInputs) {
- data = await serializationTask.deserializeModuleData(component);
- }
- frontendStrategy.registerModuleData(data);
-
- // After we've deserialized modular data, we trim the component of any
- // unnecessary dependencies.
- // Note: It is critical we wait to trim the dill until after we've
- // deserialized modular data because some of this data may reference
- // 'trimmed' elements.
- if (options.fromDill) {
- if (options.dumpUnusedLibraries) {
- dumpUnusedLibraries(component, libraries);
- }
- if (options.entryUri != null) {
- component = trimComponent(component, libraries);
- }
- }
- if (options.cfeOnly) {
- await serializationTask.serializeComponent(component);
- } else {
- await compileFromKernel(output.rootLibraryUri, libraries);
- }
+ List<ModuleData> data;
+ if (options.hasModularAnalysisInputs) {
+ data = await serializationTask.deserializeModuleData(component);
}
+ frontendStrategy.registerModuleData(data);
+
+ // After we've deserialized modular data, we trim the component of any
+ // unnecessary dependencies.
+ // Note: It is critical we wait to trim the dill until after we've
+ // deserialized modular data because some of this data may reference
+ // 'trimmed' elements.
+ dumpUnusedLibrariesAndTrimComponent(component, libraries);
+ await compileFromKernel(output.rootLibraryUri, libraries);
}
}
@@ -498,19 +480,54 @@
return closedWorld;
}
- void runModularAnalysis(
- ir.Component component, Iterable<Uri> moduleLibraries) {
+ Future<load_kernel.Output> runLoadKernel() async {
+ final input = load_kernel.Input(options, provider, reporter,
+ initializedCompilerState, forceSerializationForTesting);
+ load_kernel.Output output =
+ await loadKernelTask.measure(() async => load_kernel.run(input));
+ if (output == null || compilationFailed) return null;
+ reporter.log("Kernel load complete");
+ if (retainDataForTesting) {
+ componentForTesting = output.component;
+ }
+
+ if (options.cfeOnly) {
+ ir.Component component = output.component;
+ dumpUnusedLibrariesAndTrimComponent(component, output.libraries);
+ await serializationTask.serializeComponent(component);
+ }
+ return output;
+ }
+
+ void dumpUnusedLibrariesAndTrimComponent(
+ ir.Component component, List<Uri> libraries) {
+ if (options.fromDill) {
+ if (options.dumpUnusedLibraries) {
+ dumpUnusedLibraries(component, libraries);
+ }
+ if (options.entryUri != null) {
+ component = trimComponent(component, libraries);
+ }
+ }
+ }
+
+ void runModularAnalysis() async {
+ load_kernel.Output output = await runLoadKernel();
+ if (output == null || compilationFailed) return;
+
+ ir.Component component = output.component;
+ List<Uri> libraries = output.libraries;
+ Set<Uri> moduleLibraries = output.moduleLibraries.toSet();
_userCodeLocations
.addAll(moduleLibraries.map((module) => CodeLocation(module)));
- selfTask.measureSubtask('runModularAnalysis', () {
- var included = moduleLibraries.toSet();
- var elementMap = frontendStrategy.elementMap;
- var moduleData = computeModuleData(
- component, included, options, reporter, environment, elementMap);
- if (compilationFailed) return;
- serializationTask.testModuleSerialization(moduleData, component);
- serializationTask.serializeModuleData(moduleData, component, included);
- });
+ final input = modular_analysis.Input(
+ options, reporter, environment, component, libraries, moduleLibraries);
+ ModuleData moduleData = await selfTask.measureSubtask(
+ 'runModularAnalysis', () async => modular_analysis.run(input));
+ if (compilationFailed) return;
+ serializationTask.testModuleSerialization(moduleData, component);
+ serializationTask.serializeModuleData(
+ moduleData, component, moduleLibraries);
}
GlobalTypeInferenceResults performGlobalTypeInference(
diff --git a/pkg/compiler/lib/src/ir/modular.dart b/pkg/compiler/lib/src/ir/modular.dart
index c143853..bdb89a3 100644
--- a/pkg/compiler/lib/src/ir/modular.dart
+++ b/pkg/compiler/lib/src/ir/modular.dart
@@ -12,8 +12,6 @@
import '../diagnostics/diagnostic_listener.dart';
import '../diagnostics/messages.dart';
import '../diagnostics/source_span.dart';
-import '../kernel/element_map.dart';
-import '../environment.dart';
import '../ir/impact_data.dart';
import '../ir/static_type.dart';
import '../js_backend/annotations.dart';
@@ -92,40 +90,6 @@
return ModularMemberData(scopeModel, impactBuilderData);
}
-ModuleData computeModuleData(
- ir.Component component,
- Set<Uri> includedLibraries,
- CompilerOptions options,
- DiagnosticReporter reporter,
- Environment environment,
- KernelToElementMap elementMap) {
- var classHierarchy = elementMap.classHierarchy;
- var typeEnvironment = elementMap.typeEnvironment;
- var constantEvaluator = elementMap.constantEvaluator;
- var result = <ir.Member, ImpactBuilderData>{};
- void computeForMember(ir.Member member) {
- var scopeModel = ScopeModel.from(member, constantEvaluator);
- var annotations = processMemberAnnotations(
- options, reporter, member, computePragmaAnnotationDataFromIr(member));
- result[member] = computeModularMemberData(member,
- options: options,
- typeEnvironment: typeEnvironment,
- classHierarchy: classHierarchy,
- scopeModel: scopeModel,
- annotations: annotations)
- .impactBuilderData;
- }
-
- for (var library in component.libraries) {
- if (!includedLibraries.contains(library.importUri)) continue;
- library.members.forEach(computeForMember);
- for (var cls in library.classes) {
- cls.members.forEach(computeForMember);
- }
- }
- return ModuleData(result);
-}
-
void reportLocatedMessage(DiagnosticReporter reporter,
ir.LocatedMessage message, List<ir.LocatedMessage> context) {
DiagnosticMessage diagnosticMessage =
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 403ff04..a0a1e69 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -38,7 +38,6 @@
import '../js_backend/namer.dart';
import '../js_backend/native_data.dart';
import '../js_model/locals.dart';
-import '../kernel/kernel_strategy.dart';
import '../kernel/dart2js_target.dart';
import '../native/behavior.dart';
import '../options.dart';
@@ -58,6 +57,9 @@
@override
final DiagnosticReporter reporter;
final Environment _environment;
+ final NativeBasicDataBuilder nativeBasicDataBuilder =
+ NativeBasicDataBuilder();
+ NativeBasicData _nativeBasicData;
KCommonElements _commonElements;
KernelElementEnvironment _elementEnvironment;
DartTypeConverter _typeConverter;
@@ -101,12 +103,10 @@
final Map<ir.TreeNode, Local> localFunctionMap = {};
BehaviorBuilder _nativeBehaviorBuilder;
- final KernelFrontendStrategy _frontendStrategy;
Map<KMember, Map<ir.Expression, TypeMap>> typeMapsForTesting;
- KernelToElementMap(
- this.reporter, this._environment, this._frontendStrategy, this.options) {
+ KernelToElementMap(this.reporter, this._environment, this.options) {
_elementEnvironment = KernelElementEnvironment(this);
_typeConverter = DartTypeConverter(this);
_types = KernelDartTypes(this, options);
@@ -1422,7 +1422,16 @@
}
/// NativeBasicData is need for computation of the default super class.
- NativeBasicData get nativeBasicData => _frontendStrategy.nativeBasicData;
+ NativeBasicData get nativeBasicData {
+ if (_nativeBasicData == null) {
+ _nativeBasicData = nativeBasicDataBuilder.close(elementEnvironment);
+ assert(
+ _nativeBasicData != null,
+ failedAt(NO_LOCATION_SPANNABLE,
+ "NativeBasicData has not been computed yet."));
+ }
+ return _nativeBasicData;
+ }
/// Adds libraries in [component] to the set of libraries.
///
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 1a6b1bb..d3c918a 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -50,9 +50,6 @@
/// Front end strategy that loads '.dill' files and builds a resolved element
/// model from kernel IR nodes.
class KernelFrontendStrategy {
- final NativeBasicDataBuilder nativeBasicDataBuilder =
- NativeBasicDataBuilder();
- NativeBasicData _nativeBasicData;
final CompilerOptions _options;
final CompilerTask _compilerTask;
KernelToElementMap _elementMap;
@@ -84,7 +81,7 @@
KernelFrontendStrategy(this._compilerTask, this._options,
DiagnosticReporter reporter, env.Environment environment) {
assert(_compilerTask != null);
- _elementMap = KernelToElementMap(reporter, environment, this, _options);
+ _elementMap = KernelToElementMap(reporter, environment, _options);
_modularStrategy = KernelModularStrategy(_compilerTask, _elementMap);
_backendUsageBuilder = BackendUsageBuilderImpl(this);
noSuchMethodRegistry =
@@ -135,6 +132,7 @@
CompilerTask task, Compiler compiler) {
RuntimeTypesNeedBuilder rtiNeedBuilder = _createRuntimeTypesNeedBuilder();
BackendImpacts impacts = BackendImpacts(commonElements, compiler.options);
+ final nativeBasicData = _elementMap.nativeBasicData;
_nativeResolutionEnqueuer = NativeResolutionEnqueuer(
compiler.options,
elementEnvironment,
@@ -217,24 +215,13 @@
annotationsData);
}
- NativeBasicData get nativeBasicData {
- if (_nativeBasicData == null) {
- _nativeBasicData = nativeBasicDataBuilder.close(elementEnvironment);
- assert(
- _nativeBasicData != null,
- failedAt(NO_LOCATION_SPANNABLE,
- "NativeBasicData has not been computed yet."));
- }
- return _nativeBasicData;
- }
-
/// Registers a set of loaded libraries with this strategy.
void registerLoadedLibraries(ir.Component component, List<Uri> libraries) {
_elementMap.addComponent(component);
_irAnnotationData = processAnnotations(
ModularCore(component, _elementMap.constantEvaluator));
_annotationProcessor = KernelAnnotationProcessor(
- elementMap, nativeBasicDataBuilder, _irAnnotationData);
+ elementMap, elementMap.nativeBasicDataBuilder, _irAnnotationData);
for (Uri uri in libraries) {
LibraryEntity library = elementEnvironment.lookupLibrary(uri);
if (maybeEnableNative(library.canonicalUri)) {
diff --git a/pkg/compiler/lib/src/phase/load_kernel.dart b/pkg/compiler/lib/src/phase/load_kernel.dart
index 1db4a15..17795f7 100644
--- a/pkg/compiler/lib/src/phase/load_kernel.dart
+++ b/pkg/compiler/lib/src/phase/load_kernel.dart
@@ -50,7 +50,7 @@
/// reachable from the [rootLibraryUri].
///
/// Note that [component] may contain some libraries that are excluded here.
- final Iterable<Uri> libraries;
+ final List<Uri> libraries;
/// When running only dart2js modular analysis, returns the [Uri]s for
/// libraries loaded in the input module.
@@ -58,7 +58,7 @@
/// This excludes other libraries reachable from them that were loaded as
/// dependencies. The result of [moduleLibraries] is always a subset of
/// [libraries].
- final Iterable<Uri> moduleLibraries;
+ final List<Uri> moduleLibraries;
final fe.InitializedCompilerState initializedCompilerState;
diff --git a/pkg/compiler/lib/src/phase/modular_analysis.dart b/pkg/compiler/lib/src/phase/modular_analysis.dart
new file mode 100644
index 0000000..d7ba441
--- /dev/null
+++ b/pkg/compiler/lib/src/phase/modular_analysis.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart' as ir;
+
+import '../common.dart';
+import '../elements/entities.dart';
+import '../environment.dart';
+import '../ir/annotations.dart';
+import '../ir/impact.dart';
+import '../ir/modular.dart';
+import '../ir/scope.dart';
+import '../kernel/dart2js_target.dart';
+import '../kernel/native_basic_data.dart';
+import '../js_backend/annotations.dart';
+import '../kernel/element_map.dart';
+import '../options.dart';
+
+class Input {
+ final CompilerOptions options;
+ final DiagnosticReporter reporter;
+ final Environment environment;
+ final ir.Component component;
+ final List<Uri> libraries;
+ final Set<Uri> moduleLibraries;
+
+ Input(this.options, this.reporter, this.environment, this.component,
+ this.libraries, this.moduleLibraries);
+}
+
+KernelToElementMap _createElementMap(
+ CompilerOptions options,
+ DiagnosticReporter reporter,
+ Environment environment,
+ ir.Component component,
+ List<Uri> libraries) {
+ final elementMap = KernelToElementMap(reporter, environment, options);
+ elementMap.addComponent(component);
+ IrAnnotationData irAnnotationData =
+ processAnnotations(ModularCore(component, elementMap.constantEvaluator));
+ final annotationProcessor = KernelAnnotationProcessor(
+ elementMap, elementMap.nativeBasicDataBuilder, irAnnotationData);
+ for (final uri in libraries) {
+ LibraryEntity library = elementMap.elementEnvironment.lookupLibrary(uri);
+ if (maybeEnableNative(library.canonicalUri)) {
+ annotationProcessor.extractNativeAnnotations(library);
+ }
+ annotationProcessor.extractJsInteropAnnotations(library);
+ }
+ return elementMap;
+}
+
+ModuleData run(Input input) {
+ final options = input.options;
+ final reporter = input.reporter;
+ final elementMap = _createElementMap(
+ options, reporter, input.environment, input.component, input.libraries);
+ final result = <ir.Member, ImpactBuilderData>{};
+ void computeForMember(ir.Member member) {
+ final scopeModel = ScopeModel.from(member, elementMap.constantEvaluator);
+ final annotations = processMemberAnnotations(
+ options, reporter, member, computePragmaAnnotationDataFromIr(member));
+ result[member] = computeModularMemberData(member,
+ options: options,
+ typeEnvironment: elementMap.typeEnvironment,
+ classHierarchy: elementMap.classHierarchy,
+ scopeModel: scopeModel,
+ annotations: annotations)
+ .impactBuilderData;
+ }
+
+ for (final library in input.component.libraries) {
+ if (!input.moduleLibraries.contains(library.importUri)) continue;
+ library.members.forEach(computeForMember);
+ for (final cls in library.classes) {
+ cls.members.forEach(computeForMember);
+ }
+ }
+ return ModuleData(result);
+}
diff --git a/pkg/compiler/test/model/enqueuer_test.dart b/pkg/compiler/test/model/enqueuer_test.dart
index d6a2ac6..ac2f0c3 100644
--- a/pkg/compiler/test/model/enqueuer_test.dart
+++ b/pkg/compiler/test/model/enqueuer_test.dart
@@ -254,7 +254,7 @@
Object createConstraint(ClassEntity cls) {
return new StrongModeConstraint(compiler.frontendStrategy.commonElements,
- compiler.frontendStrategy.nativeBasicData, cls);
+ compiler.frontendStrategy.elementMap.nativeBasicData, cls);
}
for (Impact impact in impacts) {
diff --git a/pkg/compiler/test/model/open_world_test.dart b/pkg/compiler/test/model/open_world_test.dart
index d098a5d..fa190d8 100644
--- a/pkg/compiler/test/model/open_world_test.dart
+++ b/pkg/compiler/test/model/open_world_test.dart
@@ -93,7 +93,7 @@
commonElements = compiler.frontendStrategy.commonElements;
ElementEnvironment elementEnvironment =
compiler.frontendStrategy.elementEnvironment;
- nativeBasicData = compiler.frontendStrategy.nativeBasicData;
+ nativeBasicData = compiler.frontendStrategy.elementMap.nativeBasicData;
world = compiler.resolutionWorldBuilderForTesting;
ClassEntity findClass(String name) {