|  | // Copyright (c) 2019, 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. | 
|  |  | 
|  | /// Test the modular compilation pipeline of dart2js. | 
|  | /// | 
|  | /// This is a shell that runs multiple tests, one per folder under `data/`. | 
|  | import 'dart:io'; | 
|  | import 'dart:async'; | 
|  |  | 
|  | import 'package:compiler/src/commandline_options.dart'; | 
|  | import 'package:compiler/src/kernel/dart2js_target.dart'; | 
|  | import 'package:front_end/src/compute_platform_binaries_location.dart' | 
|  | show computePlatformBinariesLocation; | 
|  | import 'package:modular_test/src/io_pipeline.dart'; | 
|  | import 'package:modular_test/src/pipeline.dart'; | 
|  | import 'package:modular_test/src/suite.dart'; | 
|  | import 'package:modular_test/src/runner.dart'; | 
|  | import 'package:package_config/package_config.dart'; | 
|  |  | 
|  | String packageConfigJsonPath = ".dart_tool/package_config.json"; | 
|  | Uri sdkRoot = Platform.script.resolve("../../../"); | 
|  | Uri packageConfigUri = sdkRoot.resolve(packageConfigJsonPath); | 
|  | Options _options; | 
|  | String _dart2jsScript; | 
|  | String _kernelWorkerScript; | 
|  |  | 
|  | const dillSummaryId = DataId("sdill"); | 
|  | const dillId = DataId("dill"); | 
|  | const modularUpdatedDillId = DataId("mdill"); | 
|  | const modularDataId = DataId("mdata"); | 
|  | const closedWorldId = DataId("world"); | 
|  | const globalUpdatedDillId = DataId("gdill"); | 
|  | const globalDataId = DataId("gdata"); | 
|  | const codeId = ShardsDataId("code", 2); | 
|  | const codeId0 = ShardDataId(codeId, 0); | 
|  | const codeId1 = ShardDataId(codeId, 1); | 
|  | const jsId = DataId("js"); | 
|  | const txtId = DataId("txt"); | 
|  | const fakeRoot = 'dev-dart-app:/'; | 
|  |  | 
|  | String _packageConfigEntry(String name, Uri root, | 
|  | {Uri packageRoot, LanguageVersion version}) { | 
|  | var fields = [ | 
|  | '"name": "${name}"', | 
|  | '"rootUri": "$root"', | 
|  | if (packageRoot != null) '"packageUri": "$packageRoot"', | 
|  | if (version != null) '"languageVersion": "$version"' | 
|  | ]; | 
|  | return '{${fields.join(',')}}'; | 
|  | } | 
|  |  | 
|  | abstract class CFEStep implements IOModularStep { | 
|  | final String stepName; | 
|  |  | 
|  | CFEStep(this.stepName); | 
|  |  | 
|  | @override | 
|  | bool get needsSources => true; | 
|  |  | 
|  | @override | 
|  | bool get onlyOnMain => false; | 
|  |  | 
|  | @override | 
|  | Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri, | 
|  | List<String> flags) async { | 
|  | if (_options.verbose) print("\nstep: $stepName on $module"); | 
|  |  | 
|  | // TODO(joshualitt): Figure out a way to support package configs in | 
|  | // tests/modular. | 
|  | var packageConfig = await loadPackageConfigUri(packageConfigUri); | 
|  |  | 
|  | // We use non file-URI schemes for representeing source locations in a | 
|  | // root-agnostic way. This allows us to refer to file across modules and | 
|  | // across steps without exposing the underlying temporary folders that are | 
|  | // created by the framework. In build systems like bazel this is especially | 
|  | // important because each step may be run on a different machine. | 
|  | // | 
|  | // Files in packages are defined in terms of `package:` URIs, while | 
|  | // non-package URIs are defined using the `dart-dev-app` scheme. | 
|  | String rootScheme = module.isSdk ? 'dart-dev-sdk' : 'dev-dart-app'; | 
|  | String sourceToImportUri(Uri relativeUri) { | 
|  | if (module.isPackage) { | 
|  | var basePath = module.packageBase.path; | 
|  | var packageRelativePath = basePath == "./" | 
|  | ? relativeUri.path | 
|  | : relativeUri.path.substring(basePath.length); | 
|  | return 'package:${module.name}/$packageRelativePath'; | 
|  | } else { | 
|  | return '$rootScheme:/$relativeUri'; | 
|  | } | 
|  | } | 
|  |  | 
|  | // We create both a .packages and package_config.json file which defines | 
|  | // the location of this module if it is a package.  The CFE requires that | 
|  | // if a `package:` URI of a dependency is used in an import, then we need | 
|  | // that package entry in the associated file. However, after it checks that | 
|  | // the definition exists, the CFE will not actually use the resolved URI if | 
|  | // a library for the import URI is already found in one of the provide | 
|  | // .dill files of the dependencies. For that reason, and to ensure that | 
|  | // a step only has access to the files provided in a module, we generate a | 
|  | // config file with invalid folders for other packages. | 
|  | // TODO(sigmund): follow up with the CFE to see if we can remove the need | 
|  | // for these dummy entries.. | 
|  | // TODO(joshualitt): Generate just the json file. | 
|  | var packagesJson = []; | 
|  | var packagesContents = StringBuffer(); | 
|  | if (module.isPackage) { | 
|  | packagesContents.write('${module.name}:${module.packageBase}\n'); | 
|  | packagesJson.add(_packageConfigEntry( | 
|  | module.name, Uri.parse('../${module.packageBase}'))); | 
|  | } | 
|  |  | 
|  | Set<Module> transitiveDependencies = computeTransitiveDependencies(module); | 
|  | int unusedNum = 0; | 
|  | for (Module dependency in transitiveDependencies) { | 
|  | if (dependency.isPackage) { | 
|  | // rootUri should be ignored for dependent modules, so we pass in a | 
|  | // bogus value. | 
|  | var rootUri = Uri.parse('unused$unusedNum'); | 
|  | unusedNum++; | 
|  |  | 
|  | var dependentPackage = packageConfig[dependency.name]; | 
|  | var packageJson = dependentPackage == null | 
|  | ? _packageConfigEntry(dependency.name, rootUri) | 
|  | : _packageConfigEntry(dependentPackage.name, rootUri, | 
|  | version: dependentPackage.languageVersion); | 
|  | packagesJson.add(packageJson); | 
|  | packagesContents.write('${dependency.name}:$rootUri\n'); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (module.isPackage) { | 
|  | await File.fromUri(root.resolve(packageConfigJsonPath)) | 
|  | .create(recursive: true); | 
|  | await File.fromUri(root.resolve(packageConfigJsonPath)).writeAsString('{' | 
|  | '  "configVersion": ${packageConfig.version},' | 
|  | '  "packages": [ ${packagesJson.join(',')} ]' | 
|  | '}'); | 
|  | } | 
|  |  | 
|  | await File.fromUri(root.resolve('.packages')) | 
|  | .writeAsString('$packagesContents'); | 
|  |  | 
|  | List<String> sources; | 
|  | List<String> extraArgs = ['--packages-file', '$rootScheme:/.packages']; | 
|  | if (module.isSdk) { | 
|  | // When no flags are passed, we can skip compilation and reuse the | 
|  | // platform.dill created by build.py. | 
|  | if (flags.isEmpty) { | 
|  | var platform = computePlatformBinariesLocation() | 
|  | .resolve("dart2js_platform_unsound.dill"); | 
|  | var destination = root.resolveUri(toUri(module, outputData)); | 
|  | if (_options.verbose) { | 
|  | print('command:\ncp $platform $destination'); | 
|  | } | 
|  | await File.fromUri(platform).copy(destination.toFilePath()); | 
|  | return; | 
|  | } | 
|  | sources = requiredLibraries['dart2js'] + ['dart:core']; | 
|  | extraArgs += [ | 
|  | '--libraries-file', | 
|  | '$rootScheme:///sdk/lib/libraries.json' | 
|  | ]; | 
|  | assert(transitiveDependencies.isEmpty); | 
|  | } else { | 
|  | sources = module.sources.map(sourceToImportUri).toList(); | 
|  | } | 
|  |  | 
|  | // TODO(joshualitt): Ensure the kernel worker has some way to specify | 
|  | // --no-sound-null-safety | 
|  | List<String> args = [ | 
|  | _kernelWorkerScript, | 
|  | ...stepArguments, | 
|  | '--exclude-non-sources', | 
|  | '--multi-root', | 
|  | '$root', | 
|  | '--multi-root-scheme', | 
|  | rootScheme, | 
|  | ...extraArgs, | 
|  | '--output', | 
|  | '${toUri(module, outputData)}', | 
|  | ...(transitiveDependencies | 
|  | .expand((m) => ['--input-summary', '${toUri(m, inputData)}'])), | 
|  | ...(sources.expand((String uri) => ['--source', uri])), | 
|  | ...(flags.expand((String flag) => ['--enable-experiment', flag])), | 
|  | ]; | 
|  |  | 
|  | var result = | 
|  | await _runProcess(Platform.resolvedExecutable, args, root.toFilePath()); | 
|  | _checkExitCode(result, this, module); | 
|  | } | 
|  |  | 
|  | List<String> get stepArguments; | 
|  |  | 
|  | DataId get inputData; | 
|  |  | 
|  | DataId get outputData; | 
|  |  | 
|  | @override | 
|  | void notifyCached(Module module) { | 
|  | if (_options.verbose) print("\ncached step: $stepName on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Step that compiles sources in a module to a summary .dill file. | 
|  | class OutlineDillCompilationStep extends CFEStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [dillSummaryId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => true; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const [dillSummaryId]; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => const []; | 
|  |  | 
|  | @override | 
|  | List<String> get stepArguments => | 
|  | ['--target', 'dart2js_summary', '--summary-only']; | 
|  |  | 
|  | @override | 
|  | DataId get inputData => dillSummaryId; | 
|  |  | 
|  | @override | 
|  | DataId get outputData => dillSummaryId; | 
|  |  | 
|  | OutlineDillCompilationStep() : super('outline-dill-compilation'); | 
|  | } | 
|  |  | 
|  | // Step that compiles sources in a module to a .dill file. | 
|  | class FullDillCompilationStep extends CFEStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [dillId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => true; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const [dillSummaryId]; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => const []; | 
|  |  | 
|  | @override | 
|  | List<String> get stepArguments => | 
|  | ['--target', 'dart2js', '--no-summary', '--no-summary-only']; | 
|  |  | 
|  | @override | 
|  | DataId get inputData => dillSummaryId; | 
|  |  | 
|  | @override | 
|  | DataId get outputData => dillId; | 
|  |  | 
|  | FullDillCompilationStep() : super('full-dill-compilation'); | 
|  | } | 
|  |  | 
|  | class ModularAnalysisStep implements IOModularStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [modularDataId, modularUpdatedDillId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const [dillId]; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => const [dillId]; | 
|  |  | 
|  | @override | 
|  | bool get onlyOnMain => false; | 
|  |  | 
|  | @override | 
|  | Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri, | 
|  | List<String> flags) async { | 
|  | if (_options.verbose) print("\nstep: modular analysis on $module"); | 
|  | Set<Module> transitiveDependencies = computeTransitiveDependencies(module); | 
|  | Iterable<String> dillDependencies = | 
|  | transitiveDependencies.map((m) => '${toUri(m, dillId)}'); | 
|  | List<String> args = [ | 
|  | '--packages=${sdkRoot.toFilePath()}/.packages', | 
|  | _dart2jsScript, | 
|  | if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot', | 
|  | '${Flags.inputDill}=${toUri(module, dillId)}', | 
|  | if (dillDependencies.isNotEmpty) | 
|  | '--dill-dependencies=${dillDependencies.join(',')}', | 
|  | '--out=${toUri(module, modularUpdatedDillId)}', | 
|  | '${Flags.writeModularAnalysis}=${toUri(module, modularDataId)}', | 
|  | for (String flag in flags) '--enable-experiment=$flag', | 
|  | ]; | 
|  | var result = | 
|  | await _runProcess(Platform.resolvedExecutable, args, root.toFilePath()); | 
|  |  | 
|  | _checkExitCode(result, this, module); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void notifyCached(Module module) { | 
|  | if (_options.verbose) { | 
|  | print("cached step: dart2js modular analysis on $module"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 { | 
|  | final bool useModularAnalysis; | 
|  |  | 
|  | ComputeClosedWorldStep({this.useModularAnalysis}); | 
|  |  | 
|  | @override | 
|  | List<DataId> get resultData => const [closedWorldId, globalUpdatedDillId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => | 
|  | inputFromAnalysis(useModularAnalysis: useModularAnalysis); | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => | 
|  | inputFromAnalysis(useModularAnalysis: useModularAnalysis); | 
|  |  | 
|  | @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); | 
|  | DataId dillId = idForDill(useModularAnalysis: useModularAnalysis); | 
|  | Iterable<String> dillDependencies = | 
|  | transitiveDependencies.map((m) => '${toUri(m, dillId)}'); | 
|  | 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, dillId)}', | 
|  | for (String flag in flags) '--enable-experiment=$flag', | 
|  | '${Flags.dillDependencies}=${dillDependencies.join(',')}', | 
|  | if (useModularAnalysis) | 
|  | '${Flags.readModularAnalysis}=${dataDependencies.join(',')}', | 
|  | '${Flags.writeClosedWorld}=${toUri(module, closedWorldId)}', | 
|  | Flags.noClosedWorldInData, | 
|  | '--out=${toUri(module, globalUpdatedDillId)}', | 
|  | ]; | 
|  | 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 compute closed world on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Step that runs the dart2js modular analysis. | 
|  | class GlobalAnalysisStep implements IOModularStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [globalDataId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const [globalUpdatedDillId]; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => | 
|  | const [closedWorldId, globalUpdatedDillId]; | 
|  |  | 
|  | @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 global analysis on $module"); | 
|  | 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, globalUpdatedDillId)}', | 
|  | for (String flag in flags) '--enable-experiment=$flag', | 
|  | '${Flags.readClosedWorld}=${toUri(module, closedWorldId)}', | 
|  | '${Flags.writeData}=${toUri(module, globalDataId)}', | 
|  | // TODO(joshualitt): delete this flag after google3 roll | 
|  | '${Flags.noClosedWorldInData}', | 
|  | ]; | 
|  | 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 global analysis on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Step that invokes the dart2js code generation on the main module given the | 
|  | // results of the global analysis step and produces one shard of the codegen | 
|  | // output. | 
|  | class Dart2jsCodegenStep implements IOModularStep { | 
|  | final ShardDataId codeId; | 
|  |  | 
|  | Dart2jsCodegenStep(this.codeId); | 
|  |  | 
|  | @override | 
|  | List<DataId> get resultData => [codeId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const []; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => | 
|  | const [globalUpdatedDillId, closedWorldId, globalDataId]; | 
|  |  | 
|  | @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 backend on $module"); | 
|  | List<String> args = [ | 
|  | '--packages=${sdkRoot.toFilePath()}/.packages', | 
|  | _dart2jsScript, | 
|  | if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot', | 
|  | '${Flags.entryUri}=$fakeRoot${module.mainSource}', | 
|  | '${Flags.inputDill}=${toUri(module, globalUpdatedDillId)}', | 
|  | for (String flag in flags) '--enable-experiment=$flag', | 
|  | '${Flags.readClosedWorld}=${toUri(module, closedWorldId)}', | 
|  | '${Flags.readData}=${toUri(module, globalDataId)}', | 
|  | '${Flags.writeCodegen}=${toUri(module, codeId.dataId)}', | 
|  | '${Flags.codegenShard}=${codeId.shard}', | 
|  | '${Flags.codegenShards}=${codeId.dataId.shards}', | 
|  | ]; | 
|  | var result = | 
|  | await _runProcess(Platform.resolvedExecutable, args, root.toFilePath()); | 
|  |  | 
|  | _checkExitCode(result, this, module); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void notifyCached(Module module) { | 
|  | if (_options.verbose) print("cached step: dart2js backend on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Step that invokes the dart2js codegen enqueuer and emitter on the main module | 
|  | // given the results of the global analysis step and codegen shards. | 
|  | class Dart2jsEmissionStep implements IOModularStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [jsId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const []; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => const [ | 
|  | globalUpdatedDillId, | 
|  | closedWorldId, | 
|  | globalDataId, | 
|  | codeId0, | 
|  | codeId1 | 
|  | ]; | 
|  |  | 
|  | @override | 
|  | bool get onlyOnMain => true; | 
|  |  | 
|  | @override | 
|  | Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri, | 
|  | List<String> flags) async { | 
|  | if (_options.verbose) print("step: dart2js backend on $module"); | 
|  | List<String> args = [ | 
|  | '--packages=${sdkRoot.toFilePath()}/.packages', | 
|  | _dart2jsScript, | 
|  | if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot', | 
|  | '${Flags.entryUri}=$fakeRoot${module.mainSource}', | 
|  | '${Flags.inputDill}=${toUri(module, globalUpdatedDillId)}', | 
|  | for (String flag in flags) '${Flags.enableLanguageExperiments}=$flag', | 
|  | '${Flags.readClosedWorld}=${toUri(module, closedWorldId)}', | 
|  | '${Flags.readData}=${toUri(module, globalDataId)}', | 
|  | '${Flags.readCodegen}=${toUri(module, codeId)}', | 
|  | '${Flags.codegenShards}=${codeId.shards}', | 
|  | '--out=${toUri(module, jsId)}', | 
|  | ]; | 
|  | 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 backend on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Step that runs the output of dart2js in d8 and saves the output. | 
|  | class RunD8 implements IOModularStep { | 
|  | @override | 
|  | List<DataId> get resultData => const [txtId]; | 
|  |  | 
|  | @override | 
|  | bool get needsSources => false; | 
|  |  | 
|  | @override | 
|  | List<DataId> get dependencyDataNeeded => const []; | 
|  |  | 
|  | @override | 
|  | List<DataId> get moduleDataNeeded => const [jsId]; | 
|  |  | 
|  | @override | 
|  | bool get onlyOnMain => true; | 
|  |  | 
|  | @override | 
|  | Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri, | 
|  | List<String> flags) async { | 
|  | if (_options.verbose) print("\nstep: d8 on $module"); | 
|  | List<String> d8Args = [ | 
|  | sdkRoot | 
|  | .resolve('sdk/lib/_internal/js_runtime/lib/preambles/d8.js') | 
|  | .toFilePath(), | 
|  | root.resolveUri(toUri(module, jsId)).toFilePath(), | 
|  | ]; | 
|  | var result = await _runProcess( | 
|  | sdkRoot.resolve(_d8executable).toFilePath(), d8Args, root.toFilePath()); | 
|  |  | 
|  | _checkExitCode(result, this, module); | 
|  |  | 
|  | await File.fromUri(root.resolveUri(toUri(module, txtId))) | 
|  | .writeAsString(result.stdout); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void notifyCached(Module module) { | 
|  | if (_options.verbose) print("\ncached step: d8 on $module"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void _checkExitCode(ProcessResult result, IOModularStep step, Module module) { | 
|  | if (result.exitCode != 0 || _options.verbose) { | 
|  | stdout.write(result.stdout); | 
|  | stderr.write(result.stderr); | 
|  | } | 
|  | if (result.exitCode != 0) { | 
|  | throw "${step.runtimeType} failed on $module:\n\n" | 
|  | "stdout:\n${result.stdout}\n\n" | 
|  | "stderr:\n${result.stderr}"; | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<ProcessResult> _runProcess( | 
|  | String command, List<String> arguments, String workingDirectory) { | 
|  | if (_options.verbose) { | 
|  | print('command:\n$command ${arguments.join(' ')} from $workingDirectory'); | 
|  | } | 
|  | return Process.run(command, arguments, workingDirectory: workingDirectory); | 
|  | } | 
|  |  | 
|  | String get _d8executable { | 
|  | if (Platform.isWindows) { | 
|  | return 'third_party/d8/windows/d8.exe'; | 
|  | } else if (Platform.isLinux) { | 
|  | return 'third_party/d8/linux/d8'; | 
|  | } else if (Platform.isMacOS) { | 
|  | return 'third_party/d8/macos/d8'; | 
|  | } | 
|  | throw UnsupportedError('Unsupported platform.'); | 
|  | } | 
|  |  | 
|  | class ShardsDataId implements DataId { | 
|  | @override | 
|  | final String name; | 
|  | final int shards; | 
|  |  | 
|  | const ShardsDataId(this.name, this.shards); | 
|  |  | 
|  | @override | 
|  | String toString() => name; | 
|  | } | 
|  |  | 
|  | class ShardDataId implements DataId { | 
|  | final ShardsDataId dataId; | 
|  | final int _shard; | 
|  |  | 
|  | const ShardDataId(this.dataId, this._shard); | 
|  |  | 
|  | int get shard { | 
|  | assert(0 <= _shard && _shard < dataId.shards); | 
|  | return _shard; | 
|  | } | 
|  |  | 
|  | @override | 
|  | String get name => '${dataId.name}${shard}'; | 
|  |  | 
|  | @override | 
|  | String toString() => name; | 
|  | } | 
|  |  | 
|  | Future<void> resolveScripts(Options options) async { | 
|  | Future<String> resolve( | 
|  | String sourceUriOrPath, String relativeSnapshotPath) async { | 
|  | Uri sourceUri = sdkRoot.resolve(sourceUriOrPath); | 
|  | String result = | 
|  | sourceUri.isScheme('file') ? sourceUri.toFilePath() : sourceUriOrPath; | 
|  | if (_options.useSdk) { | 
|  | String snapshot = Uri.file(Platform.resolvedExecutable) | 
|  | .resolve(relativeSnapshotPath) | 
|  | .toFilePath(); | 
|  | if (await File(snapshot).exists()) { | 
|  | return snapshot; | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | _options = options; | 
|  | _dart2jsScript = await resolve( | 
|  | 'package:compiler/src/dart2js.dart', 'snapshots/dart2js.dart.snapshot'); | 
|  | _kernelWorkerScript = await resolve('utils/bazel/kernel_worker.dart', | 
|  | 'snapshots/kernel_worker.dart.snapshot'); | 
|  | } | 
|  |  | 
|  | String _librarySpecForSnapshot = Uri.file(Platform.resolvedExecutable) | 
|  | .resolve('../lib/libraries.json') | 
|  | .toFilePath(); |