"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter_tools/lib/src/compile.dart" (13 Nov 2020, 28407 Bytes) of package /linux/misc/flutter-1.22.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 The Flutter Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style license that can be
    3 // found in the LICENSE file.
    4 
    5 import 'dart:async';
    6 
    7 import 'package:meta/meta.dart';
    8 import 'package:package_config/package_config.dart';
    9 import 'package:process/process.dart';
   10 import 'package:usage/uuid/uuid.dart';
   11 
   12 import 'artifacts.dart';
   13 import 'base/common.dart';
   14 import 'base/context.dart';
   15 import 'base/file_system.dart';
   16 import 'base/io.dart';
   17 import 'base/logger.dart';
   18 import 'build_info.dart';
   19 import 'convert.dart';
   20 import 'globals.dart' as globals;
   21 import 'project.dart';
   22 
   23 KernelCompilerFactory get kernelCompilerFactory => context.get<KernelCompilerFactory>();
   24 
   25 class KernelCompilerFactory {
   26   const KernelCompilerFactory({
   27     @required FileSystem fileSystem,
   28     @required Artifacts artifacts,
   29     @required ProcessManager processManager,
   30     @required Logger logger,
   31   }) : _fileSystem = fileSystem,
   32        _artifacts = artifacts,
   33        _processManager = processManager,
   34        _logger = logger;
   35 
   36   final Logger _logger;
   37   final Artifacts _artifacts;
   38   final ProcessManager _processManager;
   39   final FileSystem _fileSystem;
   40 
   41   Future<KernelCompiler> create(FlutterProject flutterProject) async {
   42     return KernelCompiler(
   43       logger: _logger,
   44       artifacts: _artifacts,
   45       fileSystem: _fileSystem,
   46       processManager: _processManager,
   47     );
   48   }
   49 }
   50 
   51 /// The target model describes the set of core libraries that are available within
   52 /// the SDK.
   53 class TargetModel {
   54   /// Parse a [TargetModel] from a raw string.
   55   ///
   56   /// Throws an [AssertionError] if passed a value other than 'flutter' or
   57   /// 'flutter_runner'.
   58   factory TargetModel(String rawValue) {
   59     switch (rawValue) {
   60       case 'flutter':
   61         return flutter;
   62       case 'flutter_runner':
   63         return flutterRunner;
   64       case 'vm':
   65         return vm;
   66       case 'dartdevc':
   67         return dartdevc;
   68     }
   69     assert(false);
   70     return null;
   71   }
   72 
   73   const TargetModel._(this._value);
   74 
   75   /// The Flutter patched Dart SDK.
   76   static const TargetModel flutter = TargetModel._('flutter');
   77 
   78   /// The Fuchsia patched SDK.
   79   static const TargetModel flutterRunner = TargetModel._('flutter_runner');
   80 
   81   /// The Dart VM.
   82   static const TargetModel vm = TargetModel._('vm');
   83 
   84   /// The development compiler for JavaScript.
   85   static const TargetModel dartdevc = TargetModel._('dartdevc');
   86 
   87   final String _value;
   88 
   89   @override
   90   String toString() => _value;
   91 }
   92 
   93 class CompilerOutput {
   94   const CompilerOutput(this.outputFilename, this.errorCount, this.sources);
   95 
   96   final String outputFilename;
   97   final int errorCount;
   98   final List<Uri> sources;
   99 }
  100 
  101 enum StdoutState { CollectDiagnostic, CollectDependencies }
  102 
  103 /// Handles stdin/stdout communication with the frontend server.
  104 class StdoutHandler {
  105   StdoutHandler({
  106     @required Logger logger
  107   }) : _logger = logger {
  108     reset();
  109   }
  110 
  111   final Logger _logger;
  112 
  113   String boundaryKey;
  114   StdoutState state = StdoutState.CollectDiagnostic;
  115   Completer<CompilerOutput> compilerOutput;
  116   final List<Uri> sources = <Uri>[];
  117 
  118   bool _suppressCompilerMessages;
  119   bool _expectSources;
  120 
  121   void handler(String message) {
  122     const String kResultPrefix = 'result ';
  123     if (boundaryKey == null && message.startsWith(kResultPrefix)) {
  124       boundaryKey = message.substring(kResultPrefix.length);
  125       return;
  126     }
  127     if (message.startsWith(boundaryKey)) {
  128       if (_expectSources) {
  129         if (state == StdoutState.CollectDiagnostic) {
  130           state = StdoutState.CollectDependencies;
  131           return;
  132         }
  133       }
  134       if (message.length <= boundaryKey.length) {
  135         compilerOutput.complete(null);
  136         return;
  137       }
  138       final int spaceDelimiter = message.lastIndexOf(' ');
  139       compilerOutput.complete(
  140           CompilerOutput(
  141               message.substring(boundaryKey.length + 1, spaceDelimiter),
  142               int.parse(message.substring(spaceDelimiter + 1).trim()),
  143               sources));
  144       return;
  145     }
  146     if (state == StdoutState.CollectDiagnostic) {
  147       if (!_suppressCompilerMessages) {
  148         _logger.printError(message);
  149       } else {
  150         _logger.printTrace(message);
  151       }
  152     } else {
  153       assert(state == StdoutState.CollectDependencies);
  154       switch (message[0]) {
  155         case '+':
  156           sources.add(Uri.parse(message.substring(1)));
  157           break;
  158         case '-':
  159           sources.remove(Uri.parse(message.substring(1)));
  160           break;
  161         default:
  162           _logger.printTrace('Unexpected prefix for $message uri - ignoring');
  163       }
  164     }
  165   }
  166 
  167   // This is needed to get ready to process next compilation result output,
  168   // with its own boundary key and new completer.
  169   void reset({ bool suppressCompilerMessages = false, bool expectSources = true }) {
  170     boundaryKey = null;
  171     compilerOutput = Completer<CompilerOutput>();
  172     _suppressCompilerMessages = suppressCompilerMessages;
  173     _expectSources = expectSources;
  174     state = StdoutState.CollectDiagnostic;
  175   }
  176 }
  177 
  178 /// List the preconfigured build options for a given build mode.
  179 List<String> buildModeOptions(BuildMode mode) {
  180   switch (mode) {
  181     case BuildMode.debug:
  182       return <String>[
  183         '-Ddart.vm.profile=false',
  184         '-Ddart.vm.product=false',
  185         '--bytecode-options=source-positions,local-var-info,debugger-stops,instance-field-initializers,keep-unreachable-code,avoid-closure-call-instructions',
  186         '--enable-asserts',
  187       ];
  188     case BuildMode.profile:
  189       return <String>[
  190         '-Ddart.vm.profile=true',
  191         '-Ddart.vm.product=false',
  192         '--bytecode-options=source-positions',
  193       ];
  194     case BuildMode.release:
  195       return <String>[
  196         '-Ddart.vm.profile=false',
  197         '-Ddart.vm.product=true',
  198         '--bytecode-options=source-positions',
  199       ];
  200   }
  201   throw Exception('Unknown BuildMode: $mode');
  202 }
  203 
  204 /// A compiler interface for producing single (non-incremental) kernel files.
  205 class KernelCompiler {
  206   KernelCompiler({
  207     FileSystem fileSystem, // TODO(jonahwilliams): migrate to @required after google3
  208     Logger logger, // TODO(jonahwilliams): migrate to @required after google3
  209     ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
  210     Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
  211   }) : _logger = logger ?? globals.logger,
  212        _fileSystem = fileSystem ?? globals.fs,
  213        _artifacts = artifacts ?? globals.artifacts,
  214        _processManager = processManager ?? globals.processManager;
  215 
  216   final FileSystem _fileSystem;
  217   final Artifacts _artifacts;
  218   final ProcessManager _processManager;
  219   final Logger _logger;
  220 
  221   Future<CompilerOutput> compile({
  222     String sdkRoot,
  223     String mainPath,
  224     String outputFilePath,
  225     String depFilePath,
  226     TargetModel targetModel = TargetModel.flutter,
  227     bool linkPlatformKernelIn = false,
  228     bool aot = false,
  229     List<String> extraFrontEndOptions,
  230     List<String> fileSystemRoots,
  231     String fileSystemScheme,
  232     String initializeFromDill,
  233     String platformDill,
  234     @required String packagesPath,
  235     @required BuildMode buildMode,
  236     @required bool trackWidgetCreation,
  237     @required List<String> dartDefines,
  238     @required PackageConfig packageConfig,
  239   }) async {
  240     final String frontendServer = _artifacts.getArtifactPath(
  241       Artifact.frontendServerSnapshotForEngineDartSdk
  242     );
  243     // This is a URI, not a file path, so the forward slash is correct even on Windows.
  244     if (!sdkRoot.endsWith('/')) {
  245       sdkRoot = '$sdkRoot/';
  246     }
  247     final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary);
  248     if (!_processManager.canRun(engineDartPath)) {
  249       throwToolExit('Unable to find Dart binary at $engineDartPath');
  250     }
  251     Uri mainUri;
  252     if (packagesPath != null) {
  253       mainUri = packageConfig.toPackageUri(_fileSystem.file(mainPath).uri);
  254     }
  255     if (outputFilePath != null && !_fileSystem.isFileSync(outputFilePath)) {
  256       _fileSystem.file(outputFilePath).createSync(recursive: true);
  257     }
  258     final List<String> command = <String>[
  259       engineDartPath,
  260       '--disable-dart-dev',
  261       frontendServer,
  262       '--sdk-root',
  263       sdkRoot,
  264       '--target=$targetModel',
  265       '-Ddart.developer.causal_async_stacks=${buildMode == BuildMode.debug}',
  266       for (final Object dartDefine in dartDefines)
  267         '-D$dartDefine',
  268       ...buildModeOptions(buildMode),
  269       if (trackWidgetCreation) '--track-widget-creation',
  270       if (!linkPlatformKernelIn) '--no-link-platform',
  271       if (aot) ...<String>[
  272         '--aot',
  273         '--tfa',
  274       ],
  275       if (packagesPath != null) ...<String>[
  276         '--packages',
  277         packagesPath,
  278       ],
  279       if (outputFilePath != null) ...<String>[
  280         '--output-dill',
  281         outputFilePath,
  282       ],
  283       if (depFilePath != null && (fileSystemRoots == null || fileSystemRoots.isEmpty)) ...<String>[
  284         '--depfile',
  285         depFilePath,
  286       ],
  287       if (fileSystemRoots != null)
  288         for (final String root in fileSystemRoots) ...<String>[
  289           '--filesystem-root',
  290           root,
  291         ],
  292       if (fileSystemScheme != null) ...<String>[
  293         '--filesystem-scheme',
  294         fileSystemScheme,
  295       ],
  296       if (initializeFromDill != null) ...<String>[
  297         '--initialize-from-dill',
  298         initializeFromDill,
  299       ],
  300       if (platformDill != null) ...<String>[
  301         '--platform',
  302         platformDill,
  303       ],
  304       ...?extraFrontEndOptions,
  305       mainUri?.toString() ?? mainPath,
  306     ];
  307 
  308     _logger.printTrace(command.join(' '));
  309     final Process server = await _processManager.start(command);
  310 
  311     final StdoutHandler _stdoutHandler = StdoutHandler(logger: _logger);
  312     server.stderr
  313       .transform<String>(utf8.decoder)
  314       .listen(_logger.printError);
  315     server.stdout
  316       .transform<String>(utf8.decoder)
  317       .transform<String>(const LineSplitter())
  318       .listen(_stdoutHandler.handler);
  319     final int exitCode = await server.exitCode;
  320     if (exitCode == 0) {
  321       return _stdoutHandler.compilerOutput.future;
  322     }
  323     return null;
  324   }
  325 }
  326 
  327 /// Class that allows to serialize compilation requests to the compiler.
  328 abstract class _CompilationRequest {
  329   _CompilationRequest(this.completer);
  330 
  331   Completer<CompilerOutput> completer;
  332 
  333   Future<CompilerOutput> _run(DefaultResidentCompiler compiler);
  334 
  335   Future<void> run(DefaultResidentCompiler compiler) async {
  336     completer.complete(await _run(compiler));
  337   }
  338 }
  339 
  340 class _RecompileRequest extends _CompilationRequest {
  341   _RecompileRequest(
  342     Completer<CompilerOutput> completer,
  343     this.mainUri,
  344     this.invalidatedFiles,
  345     this.outputPath,
  346     this.packageConfig,
  347     this.suppressErrors,
  348   ) : super(completer);
  349 
  350   Uri mainUri;
  351   List<Uri> invalidatedFiles;
  352   String outputPath;
  353   PackageConfig packageConfig;
  354   bool suppressErrors;
  355 
  356   @override
  357   Future<CompilerOutput> _run(DefaultResidentCompiler compiler) async =>
  358       compiler._recompile(this);
  359 }
  360 
  361 class _CompileExpressionRequest extends _CompilationRequest {
  362   _CompileExpressionRequest(
  363     Completer<CompilerOutput> completer,
  364     this.expression,
  365     this.definitions,
  366     this.typeDefinitions,
  367     this.libraryUri,
  368     this.klass,
  369     this.isStatic,
  370   ) : super(completer);
  371 
  372   String expression;
  373   List<String> definitions;
  374   List<String> typeDefinitions;
  375   String libraryUri;
  376   String klass;
  377   bool isStatic;
  378 
  379   @override
  380   Future<CompilerOutput> _run(DefaultResidentCompiler compiler) async =>
  381       compiler._compileExpression(this);
  382 }
  383 
  384 class _CompileExpressionToJsRequest extends _CompilationRequest {
  385   _CompileExpressionToJsRequest(
  386     Completer<CompilerOutput> completer,
  387     this.libraryUri,
  388     this.line,
  389     this.column,
  390     this.jsModules,
  391     this.jsFrameValues,
  392     this.moduleName,
  393     this.expression,
  394   ) : super(completer);
  395 
  396   final String libraryUri;
  397   final int line;
  398   final int column;
  399   final Map<String, String> jsModules;
  400   final Map<String, String> jsFrameValues;
  401   final String moduleName;
  402   final String expression;
  403 
  404   @override
  405   Future<CompilerOutput> _run(DefaultResidentCompiler compiler) async =>
  406       compiler._compileExpressionToJs(this);
  407 }
  408 
  409 class _RejectRequest extends _CompilationRequest {
  410   _RejectRequest(Completer<CompilerOutput> completer) : super(completer);
  411 
  412   @override
  413   Future<CompilerOutput> _run(DefaultResidentCompiler compiler) async =>
  414       compiler._reject();
  415 }
  416 
  417 /// Wrapper around incremental frontend server compiler, that communicates with
  418 /// server via stdin/stdout.
  419 ///
  420 /// The wrapper is intended to stay resident in memory as user changes, reloads,
  421 /// restarts the Flutter app.
  422 abstract class ResidentCompiler {
  423   factory ResidentCompiler(String sdkRoot, {
  424     @required BuildMode buildMode,
  425     Logger logger, // TODO(jonahwilliams): migrate to @required after google3
  426     ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
  427     Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
  428     bool trackWidgetCreation,
  429     String packagesPath,
  430     List<String> fileSystemRoots,
  431     String fileSystemScheme,
  432     String initializeFromDill,
  433     TargetModel targetModel,
  434     bool unsafePackageSerialization,
  435     List<String> extraFrontEndOptions,
  436     String platformDill,
  437     List<String> dartDefines,
  438     String librariesSpec,
  439     // Deprecated
  440     List<String> experimentalFlags,
  441   }) = DefaultResidentCompiler;
  442 
  443   // TODO(jonahwilliams): find a better way to configure additional file system
  444   // roots from the runner.
  445   // See: https://github.com/flutter/flutter/issues/50494
  446   void addFileSystemRoot(String root);
  447 
  448   /// If invoked for the first time, it compiles Dart script identified by
  449   /// [mainPath], [invalidatedFiles] list is ignored.
  450   /// On successive runs [invalidatedFiles] indicates which files need to be
  451   /// recompiled. If [mainPath] is [null], previously used [mainPath] entry
  452   /// point that is used for recompilation.
  453   /// Binary file name is returned if compilation was successful, otherwise
  454   /// null is returned.
  455   Future<CompilerOutput> recompile(
  456     Uri mainUri,
  457     List<Uri> invalidatedFiles, {
  458     @required String outputPath,
  459     @required PackageConfig packageConfig,
  460     bool suppressErrors = false,
  461   });
  462 
  463   Future<CompilerOutput> compileExpression(
  464     String expression,
  465     List<String> definitions,
  466     List<String> typeDefinitions,
  467     String libraryUri,
  468     String klass,
  469     bool isStatic,
  470   );
  471 
  472   /// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript
  473   /// in [moduleName].
  474   ///
  475   /// Values listed in [jsFrameValues] are substituted for their names in the
  476   /// [expression].
  477   ///
  478   /// Ensures that all [jsModules] are loaded and accessible inside the
  479   /// expression.
  480   ///
  481   /// Example values of parameters:
  482   /// [moduleName] is of the form '/packages/hello_world_main.dart'
  483   /// [jsFrameValues] is a map from js variable name to its primitive value
  484   /// or another variable name, for example
  485   /// { 'x': '1', 'y': 'y', 'o': 'null' }
  486   /// [jsModules] is a map from variable name to the module name, where
  487   /// variable name is the name originally used in JavaScript to contain the
  488   /// module object, for example:
  489   /// { 'dart':'dart_sdk', 'main': '/packages/hello_world_main.dart' }
  490   /// Returns a [CompilerOutput] including the name of the file containing the
  491   /// compilation result and a number of errors.
  492   Future<CompilerOutput> compileExpressionToJs(
  493     String libraryUri,
  494     int line,
  495     int column,
  496     Map<String, String> jsModules,
  497     Map<String, String> jsFrameValues,
  498     String moduleName,
  499     String expression,
  500   );
  501 
  502   /// Should be invoked when results of compilation are accepted by the client.
  503   ///
  504   /// Either [accept] or [reject] should be called after every [recompile] call.
  505   void accept();
  506 
  507   /// Should be invoked when results of compilation are rejected by the client.
  508   ///
  509   /// Either [accept] or [reject] should be called after every [recompile] call.
  510   Future<CompilerOutput> reject();
  511 
  512   /// Should be invoked when frontend server compiler should forget what was
  513   /// accepted previously so that next call to [recompile] produces complete
  514   /// kernel file.
  515   void reset();
  516 
  517   Future<dynamic> shutdown();
  518 }
  519 
  520 @visibleForTesting
  521 class DefaultResidentCompiler implements ResidentCompiler {
  522   DefaultResidentCompiler(
  523     String sdkRoot, {
  524     @required this.buildMode,
  525     Logger logger, // TODO(jonahwilliams): migrate to @required after google3
  526     ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
  527     Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
  528     this.trackWidgetCreation = true,
  529     this.packagesPath,
  530     this.fileSystemRoots,
  531     this.fileSystemScheme,
  532     this.initializeFromDill,
  533     this.targetModel = TargetModel.flutter,
  534     this.unsafePackageSerialization,
  535     this.extraFrontEndOptions,
  536     this.platformDill,
  537     List<String> dartDefines,
  538     this.librariesSpec,
  539     // Deprecated
  540     List<String> experimentalFlags, // ignore: avoid_unused_constructor_parameters
  541   }) : assert(sdkRoot != null),
  542        _logger = logger ?? globals.logger,
  543        _processManager = processManager ?? globals.processManager,
  544        _artifacts = artifacts ?? globals.artifacts,
  545        _stdoutHandler = StdoutHandler(logger: logger),
  546        dartDefines = dartDefines ?? const <String>[],
  547        // This is a URI, not a file path, so the forward slash is correct even on Windows.
  548        sdkRoot = sdkRoot.endsWith('/') ? sdkRoot : '$sdkRoot/';
  549 
  550   final Logger _logger;
  551   final ProcessManager _processManager;
  552   final Artifacts _artifacts;
  553 
  554   final BuildMode buildMode;
  555   final bool trackWidgetCreation;
  556   final String packagesPath;
  557   final TargetModel targetModel;
  558   final List<String> fileSystemRoots;
  559   final String fileSystemScheme;
  560   final String initializeFromDill;
  561   final bool unsafePackageSerialization;
  562   final List<String> extraFrontEndOptions;
  563   final List<String> dartDefines;
  564   final String librariesSpec;
  565 
  566   @override
  567   void addFileSystemRoot(String root) {
  568     fileSystemRoots.add(root);
  569   }
  570 
  571   /// The path to the root of the Dart SDK used to compile.
  572   ///
  573   /// This is used to resolve the [platformDill].
  574   final String sdkRoot;
  575 
  576   /// The path to the platform dill file.
  577   ///
  578   /// This does not need to be provided for the normal Flutter workflow.
  579   final String platformDill;
  580 
  581   Process _server;
  582   final StdoutHandler _stdoutHandler;
  583   bool _compileRequestNeedsConfirmation = false;
  584 
  585   final StreamController<_CompilationRequest> _controller = StreamController<_CompilationRequest>();
  586 
  587   @override
  588   Future<CompilerOutput> recompile(
  589     Uri mainUri,
  590     List<Uri> invalidatedFiles, {
  591     @required String outputPath,
  592     @required PackageConfig packageConfig,
  593     bool suppressErrors = false,
  594   }) async {
  595     assert(outputPath != null);
  596     if (!_controller.hasListener) {
  597       _controller.stream.listen(_handleCompilationRequest);
  598     }
  599 
  600     final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
  601     _controller.add(
  602       _RecompileRequest(completer, mainUri, invalidatedFiles, outputPath, packageConfig, suppressErrors)
  603     );
  604     return completer.future;
  605   }
  606 
  607   Future<CompilerOutput> _recompile(_RecompileRequest request) async {
  608     _stdoutHandler.reset();
  609     _compileRequestNeedsConfirmation = true;
  610     _stdoutHandler._suppressCompilerMessages = request.suppressErrors;
  611 
  612     if (_server == null) {
  613       return _compile(
  614         request.packageConfig.toPackageUri(request.mainUri)?.toString() ?? request.mainUri.toString(),
  615         request.outputPath,
  616       );
  617     }
  618     final String inputKey = Uuid().generateV4();
  619     final String mainUri = request.packageConfig.toPackageUri(request.mainUri)?.toString()
  620       ?? request.mainUri.toString();
  621     _server.stdin.writeln('recompile $mainUri $inputKey');
  622     _logger.printTrace('<- recompile $mainUri $inputKey');
  623     for (final Uri fileUri in request.invalidatedFiles) {
  624       String message;
  625       if (fileUri.scheme == 'package') {
  626         message = fileUri.toString();
  627       } else {
  628         message = request.packageConfig.toPackageUri(fileUri)?.toString()
  629           ?? fileUri.toString();
  630       }
  631       _server.stdin.writeln(message);
  632       _logger.printTrace(message);
  633     }
  634     _server.stdin.writeln(inputKey);
  635     _logger.printTrace('<- $inputKey');
  636 
  637     return _stdoutHandler.compilerOutput.future;
  638   }
  639 
  640   final List<_CompilationRequest> _compilationQueue = <_CompilationRequest>[];
  641 
  642   Future<void> _handleCompilationRequest(_CompilationRequest request) async {
  643     final bool isEmpty = _compilationQueue.isEmpty;
  644     _compilationQueue.add(request);
  645     // Only trigger processing if queue was empty - i.e. no other requests
  646     // are currently being processed. This effectively enforces "one
  647     // compilation request at a time".
  648     if (isEmpty) {
  649       while (_compilationQueue.isNotEmpty) {
  650         final _CompilationRequest request = _compilationQueue.first;
  651         await request.run(this);
  652         _compilationQueue.removeAt(0);
  653       }
  654     }
  655   }
  656 
  657   Future<CompilerOutput> _compile(
  658     String scriptUri,
  659     String outputPath,
  660   ) async {
  661     final String frontendServer = _artifacts.getArtifactPath(
  662       Artifact.frontendServerSnapshotForEngineDartSdk
  663     );
  664     final List<String> command = <String>[
  665       _artifacts.getArtifactPath(Artifact.engineDartBinary),
  666       '--disable-dart-dev',
  667       frontendServer,
  668       '--sdk-root',
  669       sdkRoot,
  670       '--incremental',
  671       '--target=$targetModel',
  672       // TODO(jonahwilliams): remove once this becomes the default behavior
  673       // in the frontend_server.
  674       // https://github.com/flutter/flutter/issues/52693
  675       '--debugger-module-names',
  676       // TODO(annagrin): remove once this becomes the default behavior
  677       // in the frontend_server.
  678       // https://github.com/flutter/flutter/issues/59902
  679       '--experimental-emit-debug-metadata',
  680       '-Ddart.developer.causal_async_stacks=${buildMode == BuildMode.debug}',
  681       for (final Object dartDefine in dartDefines)
  682         '-D$dartDefine',
  683       if (outputPath != null) ...<String>[
  684         '--output-dill',
  685         outputPath,
  686       ],
  687       if (librariesSpec != null) ...<String>[
  688         '--libraries-spec',
  689         librariesSpec,
  690       ],
  691       if (packagesPath != null) ...<String>[
  692         '--packages',
  693         packagesPath,
  694       ],
  695       ...buildModeOptions(buildMode),
  696       if (trackWidgetCreation) '--track-widget-creation',
  697       if (fileSystemRoots != null)
  698         for (final String root in fileSystemRoots) ...<String>[
  699           '--filesystem-root',
  700           root,
  701         ],
  702       if (fileSystemScheme != null) ...<String>[
  703         '--filesystem-scheme',
  704         fileSystemScheme,
  705       ],
  706       if (initializeFromDill != null) ...<String>[
  707         '--initialize-from-dill',
  708         initializeFromDill,
  709       ],
  710       if (platformDill != null) ...<String>[
  711         '--platform',
  712         platformDill,
  713       ],
  714       if (unsafePackageSerialization == true) '--unsafe-package-serialization',
  715       ...?extraFrontEndOptions,
  716     ];
  717     _logger.printTrace(command.join(' '));
  718     _server = await _processManager.start(command);
  719     _server.stdout
  720       .transform<String>(utf8.decoder)
  721       .transform<String>(const LineSplitter())
  722       .listen(
  723         _stdoutHandler.handler,
  724         onDone: () {
  725           // when outputFilename future is not completed, but stdout is closed
  726           // process has died unexpectedly.
  727           if (!_stdoutHandler.compilerOutput.isCompleted) {
  728             _stdoutHandler.compilerOutput.complete(null);
  729             throwToolExit('the Dart compiler exited unexpectedly.');
  730           }
  731         });
  732 
  733     _server.stderr
  734       .transform<String>(utf8.decoder)
  735       .transform<String>(const LineSplitter())
  736       .listen(_logger.printError);
  737 
  738     unawaited(_server.exitCode.then((int code) {
  739       if (code != 0) {
  740         throwToolExit('the Dart compiler exited unexpectedly.');
  741       }
  742     }));
  743 
  744     _server.stdin.writeln('compile $scriptUri');
  745     _logger.printTrace('<- compile $scriptUri');
  746 
  747     return _stdoutHandler.compilerOutput.future;
  748   }
  749 
  750   @override
  751   Future<CompilerOutput> compileExpression(
  752     String expression,
  753     List<String> definitions,
  754     List<String> typeDefinitions,
  755     String libraryUri,
  756     String klass,
  757     bool isStatic,
  758   ) {
  759     if (!_controller.hasListener) {
  760       _controller.stream.listen(_handleCompilationRequest);
  761     }
  762 
  763     final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
  764     _controller.add(
  765         _CompileExpressionRequest(
  766             completer, expression, definitions, typeDefinitions, libraryUri, klass, isStatic)
  767     );
  768     return completer.future;
  769   }
  770 
  771   Future<CompilerOutput> _compileExpression(_CompileExpressionRequest request) async {
  772     _stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false);
  773 
  774     // 'compile-expression' should be invoked after compiler has been started,
  775     // program was compiled.
  776     if (_server == null) {
  777       return null;
  778     }
  779 
  780     final String inputKey = Uuid().generateV4();
  781     _server.stdin
  782       ..writeln('compile-expression $inputKey')
  783       ..writeln(request.expression);
  784     request.definitions?.forEach(_server.stdin.writeln);
  785     _server.stdin.writeln(inputKey);
  786     request.typeDefinitions?.forEach(_server.stdin.writeln);
  787     _server.stdin
  788       ..writeln(inputKey)
  789       ..writeln(request.libraryUri ?? '')
  790       ..writeln(request.klass ?? '')
  791       ..writeln(request.isStatic ?? false);
  792 
  793     return _stdoutHandler.compilerOutput.future;
  794   }
  795 
  796   @override
  797   Future<CompilerOutput> compileExpressionToJs(
  798     String libraryUri,
  799     int line,
  800     int column,
  801     Map<String, String> jsModules,
  802     Map<String, String> jsFrameValues,
  803     String moduleName,
  804     String expression,
  805   ) {
  806     if (!_controller.hasListener) {
  807       _controller.stream.listen(_handleCompilationRequest);
  808     }
  809 
  810     final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
  811     _controller.add(
  812         _CompileExpressionToJsRequest(
  813             completer, libraryUri, line, column, jsModules, jsFrameValues, moduleName, expression)
  814     );
  815     return completer.future;
  816   }
  817 
  818   Future<CompilerOutput> _compileExpressionToJs(_CompileExpressionToJsRequest request) async {
  819     _stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false);
  820 
  821     // 'compile-expression-to-js' should be invoked after compiler has been started,
  822     // program was compiled.
  823     if (_server == null) {
  824       return null;
  825     }
  826 
  827     final String inputKey = Uuid().generateV4();
  828     _server.stdin
  829       ..writeln('compile-expression-to-js $inputKey')
  830       ..writeln(request.libraryUri ?? '')
  831       ..writeln(request.line)
  832       ..writeln(request.column);
  833     request.jsModules?.forEach((String k, String v) { _server.stdin.writeln('$k:$v'); });
  834     _server.stdin.writeln(inputKey);
  835     request.jsFrameValues?.forEach((String k, String v) { _server.stdin.writeln('$k:$v'); });
  836     _server.stdin
  837       ..writeln(inputKey)
  838       ..writeln(request.moduleName ?? '')
  839       ..writeln(request.expression ?? '');
  840 
  841     return _stdoutHandler.compilerOutput.future;
  842   }
  843 
  844   @override
  845   void accept() {
  846     if (_compileRequestNeedsConfirmation) {
  847       _server.stdin.writeln('accept');
  848       _logger.printTrace('<- accept');
  849     }
  850     _compileRequestNeedsConfirmation = false;
  851   }
  852 
  853   @override
  854   Future<CompilerOutput> reject() {
  855     if (!_controller.hasListener) {
  856       _controller.stream.listen(_handleCompilationRequest);
  857     }
  858 
  859     final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
  860     _controller.add(_RejectRequest(completer));
  861     return completer.future;
  862   }
  863 
  864   Future<CompilerOutput> _reject() {
  865     if (!_compileRequestNeedsConfirmation) {
  866       return Future<CompilerOutput>.value(null);
  867     }
  868     _stdoutHandler.reset(expectSources: false);
  869     _server.stdin.writeln('reject');
  870     _logger.printTrace('<- reject');
  871     _compileRequestNeedsConfirmation = false;
  872     return _stdoutHandler.compilerOutput.future;
  873   }
  874 
  875   @override
  876   void reset() {
  877     _server?.stdin?.writeln('reset');
  878     _logger.printTrace('<- reset');
  879   }
  880 
  881   @override
  882   Future<dynamic> shutdown() async {
  883     // Server was never successfully created.
  884     if (_server == null) {
  885       return 0;
  886     }
  887     _logger.printTrace('killing pid ${_server.pid}');
  888     _server.kill();
  889     return _server.exitCode;
  890   }
  891 }