@@ -7,6 +7,7 @@ import 'dart:typed_data';
77
88import 'package:meta/meta.dart' ;
99import 'package:package_config/package_config.dart' ;
10+ import 'package:pool/pool.dart' ;
1011import 'package:process/process.dart' ;
1112import 'package:usage/uuid/uuid.dart' ;
1213
@@ -16,6 +17,7 @@ import 'base/file_system.dart';
1617import 'base/io.dart' ;
1718import 'base/logger.dart' ;
1819import 'base/platform.dart' ;
20+ import 'base/process.dart' ;
1921import 'build_info.dart' ;
2022import 'convert.dart' ;
2123
@@ -589,7 +591,7 @@ abstract class ResidentCompiler {
589591 /// Should be invoked when results of compilation are accepted by the client.
590592 ///
591593 /// Either [accept] or [reject] should be called after every [recompile] call.
592- void accept ();
594+ Future < void > accept ();
593595
594596 /// Should be invoked when results of compilation are rejected by the client.
595597 ///
@@ -599,7 +601,7 @@ abstract class ResidentCompiler {
599601 /// Should be invoked when frontend server compiler should forget what was
600602 /// accepted previously so that next call to [recompile] produces complete
601603 /// kernel file.
602- void reset ();
604+ Future < void > reset ();
603605
604606 Future <Object > shutdown ();
605607}
@@ -742,11 +744,9 @@ class DefaultResidentCompiler implements ResidentCompiler {
742744 final String inputKey = Uuid ().generateV4 ();
743745
744746 if (nativeAssets != null && nativeAssets.isNotEmpty) {
745- server.stdin.writeln ('native-assets $nativeAssets ' );
746- _logger.printTrace ('<- native-assets $nativeAssets ' );
747+ await _writelnToServerStdin ('native-assets $nativeAssets ' , printTrace: true );
747748 }
748- server.stdin.writeln ('recompile $mainUri $inputKey ' );
749- _logger.printTrace ('<- recompile $mainUri $inputKey ' );
749+ await _writelnToServerStdin ('recompile $mainUri $inputKey ' , printTrace: true );
750750 final List <Uri >? invalidatedFiles = request.invalidatedFiles;
751751 if (invalidatedFiles != null ) {
752752 for (final Uri fileUri in invalidatedFiles) {
@@ -761,8 +761,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
761761 _logger.printTrace (message);
762762 }
763763 }
764- server.stdin.writeln (inputKey);
765- _logger.printTrace ('<- $inputKey ' );
764+ await _writelnToServerStdin (inputKey, printTrace: true );
766765
767766 return _stdoutHandler.compilerOutput? .future;
768767 }
@@ -899,12 +898,10 @@ class DefaultResidentCompiler implements ResidentCompiler {
899898 }));
900899
901900 if (nativeAssetsUri != null && nativeAssetsUri.isNotEmpty) {
902- _server? .stdin.writeln ('native-assets $nativeAssetsUri ' );
903- _logger.printTrace ('<- native-assets $nativeAssetsUri ' );
901+ await _writelnToServerStdin ('native assets $nativeAssetsUri ' , printTrace: true );
904902 }
905903
906- _server? .stdin.writeln ('compile $scriptUri ' );
907- _logger.printTrace ('<- compile $scriptUri ' );
904+ await _writelnToServerStdin ('compile $scriptUri ' , printTrace: true );
908905
909906 return _stdoutHandler.compilerOutput? .future;
910907 }
@@ -945,24 +942,24 @@ class DefaultResidentCompiler implements ResidentCompiler {
945942 }
946943
947944 final String inputKey = Uuid ().generateV4 ();
948- server.stdin
949- .. writeln ( 'compile-expression $inputKey ' )
950- .. writeln ( request.expression);
951- request.definitions ? . forEach (server.stdin.writeln);
952- server.stdin. writeln ( inputKey);
953- request.definitionTypes ? . forEach (server.stdin.writeln);
954- server.stdin. writeln ( inputKey);
955- request.typeDefinitions ? . forEach (server.stdin.writeln);
956- server.stdin. writeln ( inputKey);
957- request.typeBounds ? . forEach (server.stdin.writeln);
958- server.stdin. writeln ( inputKey);
959- request.typeDefaults ? . forEach (server.stdin.writeln);
960- server.stdin
961- .. writeln (inputKey)
962- .. writeln ( request.libraryUri ?? '' )
963- .. writeln ( request.klass ?? '' )
964- .. writeln (request.method ?? '' )
965- .. writeln (request.isStatic );
945+ await _writelnToServerStdinAll ( < String > [
946+ 'compile-expression $inputKey ' ,
947+ request.expression,
948+ ... ? request.definitions,
949+ inputKey,
950+ ... ? request.definitionTypes,
951+ inputKey,
952+ ... ? request.typeDefinitions,
953+ inputKey,
954+ ... ? request.typeBounds,
955+ inputKey,
956+ ... ? request.typeDefaults,
957+ inputKey,
958+ request.libraryUri ?? '' ,
959+ request.klass ?? '' ,
960+ request.method ?? '' ,
961+ request.isStatic. toString (),
962+ ] );
966963
967964 return _stdoutHandler.compilerOutput? .future;
968965 }
@@ -1000,27 +997,28 @@ class DefaultResidentCompiler implements ResidentCompiler {
1000997 }
1001998
1002999 final String inputKey = Uuid ().generateV4 ();
1003- server.stdin
1004- ..writeln ('compile-expression-to-js $inputKey ' )
1005- ..writeln (request.libraryUri ?? '' )
1006- ..writeln (request.line)
1007- ..writeln (request.column);
1008- request.jsModules? .forEach ((String k, String v) { server.stdin.writeln ('$k :$v ' ); });
1009- server.stdin.writeln (inputKey);
1010- request.jsFrameValues? .forEach ((String k, String v) { server.stdin.writeln ('$k :$v ' ); });
1011- server.stdin
1012- ..writeln (inputKey)
1013- ..writeln (request.moduleName ?? '' )
1014- ..writeln (request.expression ?? '' );
1000+ await _writelnToServerStdinAll (< String > [
1001+ 'compile-expression-to-js $inputKey ' ,
1002+ request.libraryUri ?? '' ,
1003+ request.line.toString (),
1004+ request.column.toString (),
1005+ for (final MapEntry <String , String > entry in request.jsModules? .entries ?? < MapEntry <String , String >> [])
1006+ '${entry .key }:${entry .value }' ,
1007+ inputKey,
1008+ for (final MapEntry <String , String > entry in request.jsFrameValues? .entries ?? < MapEntry <String , String >> [])
1009+ '${entry .key }:${entry .value }' ,
1010+ inputKey,
1011+ request.moduleName ?? '' ,
1012+ request.expression ?? ''
1013+ ]);
10151014
10161015 return _stdoutHandler.compilerOutput? .future;
10171016 }
10181017
10191018 @override
1020- void accept () {
1019+ Future < void > accept () async {
10211020 if (_compileRequestNeedsConfirmation) {
1022- _server? .stdin.writeln ('accept' );
1023- _logger.printTrace ('<- accept' );
1021+ await _writelnToServerStdin ('accept' , printTrace: true );
10241022 }
10251023 _compileRequestNeedsConfirmation = false ;
10261024 }
@@ -1041,16 +1039,14 @@ class DefaultResidentCompiler implements ResidentCompiler {
10411039 return Future <CompilerOutput ?>.value ();
10421040 }
10431041 _stdoutHandler.reset (expectSources: false );
1044- _server? .stdin.writeln ('reject' );
1045- _logger.printTrace ('<- reject' );
1042+ await _writelnToServerStdin ('reject' , printTrace: true );
10461043 _compileRequestNeedsConfirmation = false ;
10471044 return _stdoutHandler.compilerOutput? .future;
10481045 }
10491046
10501047 @override
1051- void reset () {
1052- _server? .stdin.writeln ('reset' );
1053- _logger.printTrace ('<- reset' );
1048+ Future <void > reset () async {
1049+ await _writelnToServerStdin ('reset' , printTrace: true );
10541050 }
10551051
10561052 @override
@@ -1064,6 +1060,43 @@ class DefaultResidentCompiler implements ResidentCompiler {
10641060 server.kill ();
10651061 return server.exitCode;
10661062 }
1063+
1064+ Future <void > _writelnToServerStdin (String line, {
1065+ bool printTrace = false ,
1066+ }) async {
1067+ await _writelnToServerStdinAll (< String > [line], printTrace: printTrace);
1068+ }
1069+
1070+ // TODO(andrewkolos): Concurrent calls to ProcessUtils.writelnToStdinUnsafe
1071+ // against the same stdin will result in an exception. To guard against this,
1072+ // we need to force calls to run serially. Ideally, this wouldn't be
1073+ // necessary since we shouldn't have multiple concurrent writes to the
1074+ // compiler process.
1075+ // However, we do. See https://github.com/flutter/flutter/issues/152577.
1076+ final Pool _serverStdinWritePool = Pool (1 );
1077+ Future <void > _writelnToServerStdinAll (List <String > lines, {
1078+ bool printTrace = false ,
1079+ }) async {
1080+ final Process ? server = _server;
1081+ if (server == null ) {
1082+ return ;
1083+ }
1084+ final PoolResource request = await _serverStdinWritePool.request ();
1085+ try {
1086+ await ProcessUtils .writelnToStdinUnsafe (
1087+ stdin: server.stdin,
1088+ line: lines.join ('\n ' ),
1089+ );
1090+
1091+ for (final String line in lines) {
1092+ if (printTrace) {
1093+ _logger.printTrace ('<- $line ' );
1094+ }
1095+ }
1096+ } finally {
1097+ request.release ();
1098+ }
1099+ }
10671100}
10681101
10691102/// Convert a file URI into a multi-root scheme URI if provided, otherwise
0 commit comments