[dart2js] Apply mixin transform globally.

This cl applies the mixin transform only on the full dill. In addition,
this cl also adds a concatenate dills step to more closely match
modular builds in production.

Change-Id: Icb37c5e2180c9e8246334143a6f772a203f80bf9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/238320
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
This commit is contained in:
Joshua Litt 2022-03-23 18:38:51 +00:00 committed by Commit Bot
parent d7935c209d
commit 0ad7f27990
10 changed files with 142 additions and 34 deletions

View file

@ -70,8 +70,10 @@ class Dart2jsTarget extends Target {
final String name;
final CompilerOptions? options;
final bool canPerformGlobalTransforms;
Dart2jsTarget(this.name, this.flags, {this.options});
Dart2jsTarget(this.name, this.flags,
{this.options, this.canPerformGlobalTransforms = true});
@override
bool get enableNoSuchMethodForwarders => true;
@ -157,8 +159,10 @@ class Dart2jsTarget extends Target {
}
lowering.transformLibraries(libraries, coreTypes, hierarchy, options);
logger?.call("Lowering transformations performed");
transformMixins.transformLibraries(libraries);
logger?.call("Mixin transformations performed");
if (canPerformGlobalTransforms) {
transformMixins.transformLibraries(libraries);
logger?.call("Mixin transformations performed");
}
}
@override

View file

@ -170,9 +170,7 @@ class CompilerOptions implements DiagnosticOptions {
bool get fromDill {
var targetPath = compilationTarget!.path;
return targetPath.endsWith('.dill') ||
targetPath.endsWith('.gdill') ||
targetPath.endsWith('.mdill');
return targetPath.endsWith('.dill');
}
/// Location of the package configuration file.

View file

@ -17,6 +17,8 @@ import '../commandline_options.dart';
import '../common.dart';
import '../kernel/front_end_adapter.dart';
import '../kernel/dart2js_target.dart' show Dart2jsTarget;
import '../kernel/transformations/clone_mixin_methods_with_super.dart'
as transformMixins show transformLibraries;
import '../options.dart';
class Input {
@ -121,6 +123,10 @@ class _LoadFromKernelResult {
this.component, this.entryLibrary, this.moduleLibraries);
}
void _doGlobalTransforms(Component component) {
transformMixins.transformLibraries(component.libraries);
}
Future<_LoadFromKernelResult> _loadFromKernel(CompilerOptions options,
api.CompilerInput compilerInput, String targetName) async {
Library entryLibrary;
@ -178,6 +184,11 @@ Future<_LoadFromKernelResult> _loadFromKernel(CompilerOptions options,
var mainMethod = _findMainMethod(entryLibrary);
component.setMainMethodAndMode(mainMethod, true, component.mode);
}
// We apply global transforms when running phase 0.
if (options.cfeOnly) {
_doGlobalTransforms(component);
}
return _LoadFromKernelResult(component, entryLibrary, moduleLibraries);
}
@ -195,7 +206,8 @@ Future<_LoadFromSourceResult> _loadFromSource(
fe.InitializedCompilerState initializedCompilerState,
String targetName) async {
bool verbose = false;
Target target = Dart2jsTarget(targetName, TargetFlags(), options: options);
Target target = Dart2jsTarget(targetName, TargetFlags(),
options: options, canPerformGlobalTransforms: true);
fe.FileSystem fileSystem = CompilerFileSystem(compilerInput);
fe.Verbosity verbosity = options.verbosity;
fe.DiagnosticMessageHandler onDiagnostic = (fe.DiagnosticMessage message) {

View file

@ -23,6 +23,7 @@ main(List<String> args) async {
OutlineDillCompilationStep(),
FullDillCompilationStep(),
ModularAnalysisStep(),
ConcatenateDillsStep(useModularAnalysis: true),
ComputeClosedWorldStep(useModularAnalysis: true),
GlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),

View file

@ -25,13 +25,14 @@ Options _options;
String _dart2jsScript;
String _kernelWorkerScript;
const dillSummaryId = DataId("sdill");
const dillId = DataId("dill");
const modularUpdatedDillId = DataId("mdill");
const modularDataId = DataId("mdata");
const dillSummaryId = DataId("summary.dill");
const dillId = DataId("full.dill");
const fullDillId = DataId("concatenate.dill");
const modularUpdatedDillId = DataId("modular.dill");
const modularDataId = DataId("modular.data");
const closedWorldId = DataId("world");
const globalUpdatedDillId = DataId("gdill");
const globalDataId = DataId("gdata");
const globalUpdatedDillId = DataId("global.dill");
const globalDataId = DataId("global.data");
const codeId = ShardsDataId("code", 2);
const codeId0 = ShardDataId(codeId, 0);
const codeId1 = ShardDataId(codeId, 1);
@ -305,44 +306,36 @@ class ModularAnalysisStep implements IOModularStep {
}
}
DataId idForDill({bool useModularAnalysis}) =>
useModularAnalysis ? modularUpdatedDillId : dillId;
List<DataId> inputFromAnalysis({bool useModularAnalysis = false}) => [
idForDill(useModularAnalysis: useModularAnalysis),
if (useModularAnalysis) modularDataId,
];
// Step that invokes the dart2js closed world computation.
class ComputeClosedWorldStep implements IOModularStep {
class ConcatenateDillsStep implements IOModularStep {
final bool useModularAnalysis;
ComputeClosedWorldStep({this.useModularAnalysis});
DataId get idForDill => useModularAnalysis ? modularUpdatedDillId : dillId;
List<DataId> get dependencies => [idForDill];
@override
List<DataId> get resultData => const [closedWorldId, globalUpdatedDillId];
List<DataId> get resultData => const [fullDillId];
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded =>
inputFromAnalysis(useModularAnalysis: useModularAnalysis);
List<DataId> get dependencyDataNeeded => dependencies;
@override
List<DataId> get moduleDataNeeded =>
inputFromAnalysis(useModularAnalysis: useModularAnalysis);
List<DataId> get moduleDataNeeded => dependencies;
@override
bool get onlyOnMain => true;
ConcatenateDillsStep({this.useModularAnalysis});
@override
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
List<String> flags) async {
if (_options.verbose)
print("\nstep: dart2js compute closed world on $module");
if (_options.verbose) print("\nstep: dart2js concatenate dills on $module");
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
DataId dillId = idForDill(useModularAnalysis: useModularAnalysis);
DataId dillId = idForDill;
Iterable<String> dillDependencies =
transitiveDependencies.map((m) => '${toUri(m, dillId)}');
List<String> dataDependencies = transitiveDependencies
@ -358,8 +351,66 @@ class ComputeClosedWorldStep implements IOModularStep {
'${Flags.inputDill}=${toUri(module, dillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.dillDependencies}=${dillDependencies.join(',')}',
if (useModularAnalysis)
'${Flags.readModularAnalysis}=${dataDependencies.join(',')}',
'${Flags.cfeOnly}',
'--out=${toUri(module, fullDillId)}',
];
var result =
await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
_checkExitCode(result, this, module);
}
@override
void notifyCached(Module module) {
if (_options.verbose)
print("\ncached step: dart2js concatenate dills on $module");
}
}
// Step that invokes the dart2js closed world computation.
class ComputeClosedWorldStep implements IOModularStep {
final bool useModularAnalysis;
ComputeClosedWorldStep({this.useModularAnalysis});
List<DataId> get dependencies => [
fullDillId,
if (useModularAnalysis) modularDataId,
];
@override
List<DataId> get resultData => const [closedWorldId, globalUpdatedDillId];
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded => dependencies;
@override
List<DataId> get moduleDataNeeded => dependencies;
@override
bool get onlyOnMain => true;
@override
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
List<String> flags) async {
if (_options.verbose)
print("\nstep: dart2js compute closed world on $module");
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
List<String> dataDependencies = transitiveDependencies
.map((m) => '${toUri(m, modularDataId)}')
.toList();
dataDependencies.add('${toUri(module, modularDataId)}');
List<String> args = [
'--packages=${sdkRoot.toFilePath()}/.packages',
_dart2jsScript,
// TODO(sigmund): remove this dependency on libraries.json
if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
'${Flags.entryUri}=$fakeRoot${module.mainSource}',
'${Flags.inputDill}=${toUri(module, fullDillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.writeClosedWorld}=${toUri(module, closedWorldId)}',
Flags.noClosedWorldInData,
'--out=${toUri(module, globalUpdatedDillId)}',

View file

@ -22,6 +22,7 @@ main(List<String> args) async {
IOPipeline([
OutlineDillCompilationStep(),
FullDillCompilationStep(),
ConcatenateDillsStep(useModularAnalysis: false),
ComputeClosedWorldStep(useModularAnalysis: false),
GlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),

View file

@ -0,0 +1,9 @@
// 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 'm.dart';
class B extends A {}
class C extends B with M {}

View file

@ -0,0 +1,12 @@
// 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.
class A {
String foo() => 'A';
}
mixin M on A {
@override
String foo() => 'M' + super.foo();
}

View file

@ -0,0 +1,12 @@
// Copyright (c) 2021, 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:expect/expect.dart';
import 'b.dart';
main() {
C c = C();
Expect.equals('MA', c.foo());
}

View file

@ -0,0 +1,8 @@
# Copyright (c) 2021, 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.
dependencies:
main: [b, m, expect]
b: [m]
m: []