[dart2js] Disable kernel transformer when using modular analysis.

Mutating the kernel AST can cause serialization and deserialization to
go out of sync when modular analysis is enabled, crashing dart2js.

Change-Id: If19afabacf1cb120a6804bd12ef268316de41f1b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286862
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Mayank Patke 2023-03-07 19:36:10 +00:00 committed by Commit Queue
parent 3c633384d3
commit 6414db5327

View file

@ -397,7 +397,7 @@ class Compiler {
} }
Future<load_kernel.Output?> produceKernel() async { Future<load_kernel.Output?> produceKernel() async {
if (options.readClosedWorldUri == null) { if (shouldComputeClosedWorld) {
load_kernel.Output? output = await loadKernel(); load_kernel.Output? output = await loadKernel();
if (output == null || compilationFailed) return null; if (output == null || compilationFailed) return null;
ir.Component component = output.component; ir.Component component = output.component;
@ -445,42 +445,37 @@ class Compiler {
bool shouldStopAfterLoadKernel(load_kernel.Output? output) => bool shouldStopAfterLoadKernel(load_kernel.Output? output) =>
output == null || compilationFailed || options.cfeOnly; output == null || compilationFailed || options.cfeOnly;
void simplifyConstConditionals(load_kernel.Output output) { void simplifyConstConditionals(ir.Component component) {
if (options.readClosedWorldUri == null) { void reportMessage(
void reportMessage( fe.LocatedMessage message, List<fe.LocatedMessage>? context) {
fe.LocatedMessage message, List<fe.LocatedMessage>? context) { reportLocatedMessage(reporter, message, context);
reportLocatedMessage(reporter, message, context);
}
bool shouldNotInline(ir.TreeNode node) {
if (node is! ir.Annotatable) {
return false;
}
return computePragmaAnnotationDataFromIr(node).any((pragma) =>
pragma == const PragmaAnnotationData('noInline') ||
pragma == const PragmaAnnotationData('never-inline'));
}
// No existing closed world means we're in phase 1, so run the
// transformer.
fe.ConstConditionalSimplifier(
const Dart2jsDartLibrarySupport(),
const Dart2jsConstantsBackend(
supportsUnevaluatedConstants: false),
output.component,
reportMessage,
environmentDefines: environment.definitions,
evaluationMode: options.useLegacySubtyping
? fe.EvaluationMode.weak
: fe.EvaluationMode.strong,
shouldNotInline: shouldNotInline)
.run();
} }
// If the closed world is deserialized instead, then the input .dill should bool shouldNotInline(ir.TreeNode node) {
// already have the modified AST. if (node is! ir.Annotatable) {
return false;
}
return computePragmaAnnotationDataFromIr(node).any((pragma) =>
pragma == const PragmaAnnotationData('noInline') ||
pragma == const PragmaAnnotationData('never-inline'));
}
fe.ConstConditionalSimplifier(
const Dart2jsDartLibrarySupport(),
const Dart2jsConstantsBackend(supportsUnevaluatedConstants: false),
component,
reportMessage,
environmentDefines: environment.definitions,
evaluationMode: options.useLegacySubtyping
? fe.EvaluationMode.weak
: fe.EvaluationMode.strong,
shouldNotInline: shouldNotInline)
.run();
} }
bool get usingModularAnalysis =>
options.modularMode || options.hasModularAnalysisInputs;
Future<ModuleData> runModularAnalysis( Future<ModuleData> runModularAnalysis(
load_kernel.Output output, Set<Uri> moduleLibraries) async { load_kernel.Output output, Set<Uri> moduleLibraries) async {
ir.Component component = output.component; ir.Component component = output.component;
@ -600,11 +595,28 @@ class Compiler {
globalTypeInferenceResultsData); globalTypeInferenceResultsData);
} }
bool get shouldComputeClosedWorld => options.readClosedWorldUri == null;
Future<DataAndIndices<JClosedWorld>?> produceClosedWorld( Future<DataAndIndices<JClosedWorld>?> produceClosedWorld(
load_kernel.Output output, ModuleData? moduleData) async { load_kernel.Output output, ModuleData? moduleData) async {
ir.Component component = output.component; ir.Component component = output.component;
DataAndIndices<JClosedWorld> closedWorldAndIndices; DataAndIndices<JClosedWorld> closedWorldAndIndices;
if (options.readClosedWorldUri == null) { if (shouldComputeClosedWorld) {
if (!usingModularAnalysis) {
// If we're deserializing the closed world, the input .dill already
// contains the modified AST, so the transformer only needs to run if
// the closed world is being computed from scratch.
//
// However, the transformer is not currently compatible with modular
// analysis. When modular analysis is enabled in Blaze, some aspects run
// before this phase of the compiler. This can cause dart2js to crash if
// the kernel AST is mutated, since we will attempt to serialize and
// deserialize against different ASTs.
//
// TODO(fishythefish): Make this compatible with modular analysis.
simplifyConstConditionals(component);
}
Uri rootLibraryUri = output.rootLibraryUri!; Uri rootLibraryUri = output.rootLibraryUri!;
List<Uri> libraries = output.libraries!; List<Uri> libraries = output.libraries!;
final closedWorld = final closedWorld =
@ -724,19 +736,17 @@ class Compiler {
final output = await produceKernel(); final output = await produceKernel();
if (shouldStopAfterLoadKernel(output)) return; if (shouldStopAfterLoadKernel(output)) return;
simplifyConstConditionals(output!);
// Run modular analysis. This may be null if modular analysis was not // Run modular analysis. This may be null if modular analysis was not
// requested for this pipeline. // requested for this pipeline.
ModuleData? moduleData; ModuleData? moduleData;
if (options.modularMode || options.hasModularAnalysisInputs) { if (usingModularAnalysis) {
moduleData = await produceModuleData(output); moduleData = await produceModuleData(output!);
} }
if (shouldStopAfterModularAnalysis) return; if (shouldStopAfterModularAnalysis) return;
// Compute closed world. // Compute closed world.
DataAndIndices<JClosedWorld>? closedWorldAndIndices = DataAndIndices<JClosedWorld>? closedWorldAndIndices =
await produceClosedWorld(output, moduleData); await produceClosedWorld(output!, moduleData);
if (shouldStopAfterClosedWorld(closedWorldAndIndices)) return; if (shouldStopAfterClosedWorld(closedWorldAndIndices)) return;
// Run global analysis. // Run global analysis.