[CFE] Fix using part as entry with experimental invalidation Change-Id: I813aecd06aa2e7c4cc6b1aadff50a77268096ca6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241743 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart index ac929fb..4586498 100644 --- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart +++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -288,9 +288,11 @@ if (_resetTicker) { _ticker.reset(); } - entryPoints ??= context.options.inputs; + List<Uri>? entryPointsSavedForLaterOverwrite = entryPoints; return context .runInContext<IncrementalCompilerResult>((CompilerContext c) async { + List<Uri> entryPoints = + entryPointsSavedForLaterOverwrite ?? context.options.inputs; if (_computeDeltaRunOnce && _initializedForExpressionCompilationOnly) { throw new StateError("Initialized for expression compilation: " "cannot do another general compile."); @@ -311,23 +313,7 @@ Set<Uri?> invalidatedUris = this._invalidatedUris.toSet(); _invalidateNotKeptUserBuilders(invalidatedUris); ReusageResult? reusedResult = _computeReusedLibraries( - lastGoodKernelTarget, - _userBuilders, - invalidatedUris, - uriTranslator, - entryPoints!); - - // Use the reused libraries to re-write entry-points. - if (reusedResult.arePartsUsedAsEntryPoints()) { - for (int i = 0; i < entryPoints!.length; i++) { - Uri entryPoint = entryPoints![i]; - Uri? redirect = - reusedResult.getLibraryUriForPartUsedAsEntryPoint(entryPoint); - if (redirect != null) { - entryPoints![i] = redirect; - } - } - } + lastGoodKernelTarget, _userBuilders, invalidatedUris, uriTranslator); // Experimental invalidation initialization (e.g. figure out if we can). _benchmarker @@ -338,6 +324,10 @@ experimentalInvalidation?.missingSources.length ?? 0); _benchmarker + ?.enterPhase(BenchmarkPhases.incremental_rewriteEntryPointsIfPart); + _rewriteEntryPointsIfPart(entryPoints, reusedResult); + + _benchmarker ?.enterPhase(BenchmarkPhases.incremental_invalidatePrecompiledMacros); await _invalidatePrecompiledMacros( c.options, reusedResult.notReusedLibraries); @@ -375,11 +365,11 @@ while (true) { _benchmarker?.enterPhase(BenchmarkPhases.incremental_setupInLoop); currentKernelTarget = _setupNewKernelTarget(c, uriTranslator, hierarchy, - reusedLibraries, experimentalInvalidation, entryPoints!.first); + reusedLibraries, experimentalInvalidation, entryPoints.first); Map<LibraryBuilder, List<LibraryBuilder>>? rebuildBodiesMap = _experimentalInvalidationCreateRebuildBodiesBuilders( currentKernelTarget, experimentalInvalidation, uriTranslator); - entryPoints = currentKernelTarget.setEntryPoints(entryPoints!); + entryPoints = currentKernelTarget.setEntryPoints(entryPoints); // TODO(johnniwinther,jensj): Ensure that the internal state of the // incremental compiler is consistent across 1 or more macro @@ -477,7 +467,7 @@ currentKernelTarget, data.component != null || fullComponent, compiledLibraries, - entryPoints!, + entryPoints, reusedLibraries, hierarchy, uriTranslator, @@ -540,6 +530,21 @@ }); } + void _rewriteEntryPointsIfPart( + List<Uri> entryPoints, ReusageResult reusedResult) { + for (int i = 0; i < entryPoints.length; i++) { + Uri entryPoint = entryPoints[i]; + LibraryBuilder? parent = reusedResult.partUriToParent[entryPoint]; + if (parent == null) continue; + // TODO(jensj): .contains on a list is O(n). + // It will only be done for each entry point that's a part though, i.e. + // most likely very rarely. + if (reusedResult.reusedLibraries.contains(parent)) { + entryPoints[i] = parent.importUri; + } + } + } + /// Convert every SourceLibraryBuilder to a DillLibraryBuilder. /// As we always do this, this will only be the new ones. /// @@ -1156,6 +1161,9 @@ /// Figure out if we can (and was asked to) do experimental invalidation. /// Note that this returns (future or) [null] if we're not doing experimental /// invalidation. + /// + /// Note that - when doing experimental invalidation - [reusedResult] is + /// updated. Future<ExperimentalInvalidation?> _initializeExperimentalInvalidation( ReusageResult reusedResult, CompilerContext c) async { Set<LibraryBuilder>? rebuildBodies; @@ -1263,7 +1271,6 @@ // to rebuild only the body of. // TODO(jensj): We can probably add this to the rebuildBodies // list and just rebuild that library too. - // print("Usage of mixin in ${lib.importUri}"); return null; } } @@ -2020,8 +2027,7 @@ IncrementalKernelTarget? lastGoodKernelTarget, Map<Uri, LibraryBuilder>? _userBuilders, Set<Uri?> invalidatedUris, - UriTranslator uriTranslator, - List<Uri> entryPoints) { + UriTranslator uriTranslator) { Set<Uri> seenUris = new Set<Uri>(); List<LibraryBuilder> reusedLibraries = <LibraryBuilder>[]; for (int i = 0; i < _platformBuilders!.length; i++) { @@ -2179,26 +2185,8 @@ if (!seenUris.add(builder.importUri)) continue; reusedLibraries.add(builder); } - - ReusageResult result = new ReusageResult( - notReusedLibraries, - directlyInvalidated, - invalidatedBecauseOfPackageUpdate, - reusedLibraries); - - for (Uri entryPoint in entryPoints) { - LibraryBuilder? parent = partUriToParent[entryPoint]; - if (parent == null) continue; - // TODO(jensj): .contains on a list is O(n). - // It will only be done for each entry point that's a part though, i.e. - // most likely very rarely. - if (reusedLibraries.contains(parent)) { - result.registerLibraryUriForPartUsedAsEntryPoint( - entryPoint, parent.importUri); - } - } - - return result; + return new ReusageResult(notReusedLibraries, directlyInvalidated, + invalidatedBecauseOfPackageUpdate, reusedLibraries, partUriToParent); } @override @@ -2312,17 +2300,21 @@ final Set<LibraryBuilder> directlyInvalidated; final bool invalidatedBecauseOfPackageUpdate; final List<LibraryBuilder> reusedLibraries; - final Map<Uri, Uri> _reusedLibrariesPartsToParentForEntryPoints; + final Map<Uri?, LibraryBuilder> partUriToParent; ReusageResult.reusedLibrariesOnly(this.reusedLibraries) : notReusedLibraries = const {}, directlyInvalidated = const {}, invalidatedBecauseOfPackageUpdate = false, - _reusedLibrariesPartsToParentForEntryPoints = const {}; + partUriToParent = const {}; - ReusageResult(this.notReusedLibraries, this.directlyInvalidated, - this.invalidatedBecauseOfPackageUpdate, this.reusedLibraries) - : _reusedLibrariesPartsToParentForEntryPoints = {}, + ReusageResult( + this.notReusedLibraries, + this.directlyInvalidated, + this.invalidatedBecauseOfPackageUpdate, + this.reusedLibraries, + this.partUriToParent) + : // ignore: unnecessary_null_comparison assert(notReusedLibraries != null), // ignore: unnecessary_null_comparison @@ -2330,18 +2322,9 @@ // ignore: unnecessary_null_comparison assert(invalidatedBecauseOfPackageUpdate != null), // ignore: unnecessary_null_comparison - assert(reusedLibraries != null); - - void registerLibraryUriForPartUsedAsEntryPoint( - Uri entryPoint, Uri importUri) { - _reusedLibrariesPartsToParentForEntryPoints[entryPoint] = importUri; - } - - bool arePartsUsedAsEntryPoints() => - _reusedLibrariesPartsToParentForEntryPoints.isNotEmpty; - - Uri? getLibraryUriForPartUsedAsEntryPoint(Uri entryPoint) => - _reusedLibrariesPartsToParentForEntryPoints[entryPoint]; + assert(reusedLibraries != null), + // ignore: unnecessary_null_comparison + assert(partUriToParent != null); } class ExperimentalInvalidation {
diff --git a/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart b/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart index 5966303..8008f364 100644 --- a/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart +++ b/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart
@@ -200,6 +200,7 @@ incremental_ensurePlatform, incremental_invalidate, incremental_experimentalInvalidation, + incremental_rewriteEntryPointsIfPart, incremental_invalidatePrecompiledMacros, incremental_cleanup, incremental_loadEnsureLoadedComponents,
diff --git a/pkg/front_end/testcases/incremental/part_as_entry_2.yaml b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml new file mode 100644 index 0000000..0def2e8 --- /dev/null +++ b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml
@@ -0,0 +1,42 @@ +# 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.md file. + +type: newworld +worlds: + - entry: entry.dart + experiments: alternative-invalidation-strategy + checkEntries: false + sources: + entry.dart: | + part of "lib.dart"; + lib.dart: | + import 'lib1.dart'; + export 'lib1.dart'; + part "entry.dart"; + lib1.dart: | + import 'lib.dart'; + main() { + print("Hello, World!"); + } + expectedLibraryCount: 2 + + - entry: entry.dart + experiments: alternative-invalidation-strategy + checkEntries: false + worldType: updated + expectInitializeFromDill: false + invalidate: + - lib.dart + expectedLibraryCount: 2 + expectsRebuildBodiesOnly: true + + - entry: entry.dart + experiments: alternative-invalidation-strategy + checkEntries: false + worldType: updated + expectInitializeFromDill: false + invalidate: + - lib1.dart + expectedLibraryCount: 2 + expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.1.expect b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.1.expect new file mode 100644 index 0000000..066a54b --- /dev/null +++ b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.1.expect
@@ -0,0 +1,17 @@ +main = lib1::main; +library from "org-dartlang-test:///lib.dart" as lib { +additionalExports = (lib1::main) + + import "org-dartlang-test:///lib1.dart"; + export "org-dartlang-test:///lib1.dart"; + + part entry.dart; +} +library from "org-dartlang-test:///lib1.dart" as lib1 { + + import "org-dartlang-test:///lib.dart"; + + static method main() → dynamic { + dart.core::print("Hello, World!"); + } +}
diff --git a/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.2.expect b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.2.expect new file mode 100644 index 0000000..066a54b --- /dev/null +++ b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.2.expect
@@ -0,0 +1,17 @@ +main = lib1::main; +library from "org-dartlang-test:///lib.dart" as lib { +additionalExports = (lib1::main) + + import "org-dartlang-test:///lib1.dart"; + export "org-dartlang-test:///lib1.dart"; + + part entry.dart; +} +library from "org-dartlang-test:///lib1.dart" as lib1 { + + import "org-dartlang-test:///lib.dart"; + + static method main() → dynamic { + dart.core::print("Hello, World!"); + } +}
diff --git a/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.3.expect b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.3.expect new file mode 100644 index 0000000..066a54b --- /dev/null +++ b/pkg/front_end/testcases/incremental/part_as_entry_2.yaml.world.3.expect
@@ -0,0 +1,17 @@ +main = lib1::main; +library from "org-dartlang-test:///lib.dart" as lib { +additionalExports = (lib1::main) + + import "org-dartlang-test:///lib1.dart"; + export "org-dartlang-test:///lib1.dart"; + + part entry.dart; +} +library from "org-dartlang-test:///lib1.dart" as lib1 { + + import "org-dartlang-test:///lib.dart"; + + static method main() → dynamic { + dart.core::print("Hello, World!"); + } +}