Skip to content

Commit d20ec4c

Browse files
author
Jonah Williams
authored
[flutter_tools] read expression compilation results into memory before starting next compilation (flutter#77867)
1 parent 2daac92 commit d20ec4c

File tree

10 files changed

+111
-39
lines changed

10 files changed

+111
-39
lines changed

packages/flutter_tools/lib/src/compile.dart

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// @dart = 2.8
66

77
import 'dart:async';
8+
import 'dart:typed_data';
89

910
import 'package:meta/meta.dart';
1011
import 'package:package_config/package_config.dart';
@@ -65,24 +66,30 @@ class TargetModel {
6566
}
6667

6768
class CompilerOutput {
68-
const CompilerOutput(this.outputFilename, this.errorCount, this.sources);
69+
const CompilerOutput(this.outputFilename, this.errorCount, this.sources, {this.expressionData});
6970

7071
final String outputFilename;
7172
final int errorCount;
7273
final List<Uri> sources;
74+
75+
/// This field is only non-null for expression compilation requests.
76+
final Uint8List expressionData;
7377
}
7478

7579
enum StdoutState { CollectDiagnostic, CollectDependencies }
7680

7781
/// Handles stdin/stdout communication with the frontend server.
7882
class StdoutHandler {
7983
StdoutHandler({
80-
@required Logger logger
81-
}) : _logger = logger {
84+
@required Logger logger,
85+
@required FileSystem fileSystem,
86+
}) : _logger = logger,
87+
_fileSystem = fileSystem {
8288
reset();
8389
}
8490

8591
final Logger _logger;
92+
final FileSystem _fileSystem;
8693

8794
String boundaryKey;
8895
StdoutState state = StdoutState.CollectDiagnostic;
@@ -91,6 +98,7 @@ class StdoutHandler {
9198

9299
bool _suppressCompilerMessages;
93100
bool _expectSources;
101+
bool _readFile;
94102

95103
void handler(String message) {
96104
const String kResultPrefix = 'result ';
@@ -110,11 +118,19 @@ class StdoutHandler {
110118
return;
111119
}
112120
final int spaceDelimiter = message.lastIndexOf(' ');
113-
compilerOutput.complete(
114-
CompilerOutput(
115-
message.substring(boundaryKey.length + 1, spaceDelimiter),
116-
int.parse(message.substring(spaceDelimiter + 1).trim()),
117-
sources));
121+
final String fileName = message.substring(boundaryKey.length + 1, spaceDelimiter);
122+
final int errorCount = int.parse(message.substring(spaceDelimiter + 1).trim());
123+
Uint8List expressionData;
124+
if (_readFile) {
125+
expressionData = _fileSystem.file(fileName).readAsBytesSync();
126+
}
127+
final CompilerOutput output = CompilerOutput(
128+
fileName,
129+
errorCount,
130+
sources,
131+
expressionData: expressionData,
132+
);
133+
compilerOutput.complete(output);
118134
return;
119135
}
120136
if (state == StdoutState.CollectDiagnostic) {
@@ -140,11 +156,12 @@ class StdoutHandler {
140156

141157
// This is needed to get ready to process next compilation result output,
142158
// with its own boundary key and new completer.
143-
void reset({ bool suppressCompilerMessages = false, bool expectSources = true }) {
159+
void reset({ bool suppressCompilerMessages = false, bool expectSources = true, bool readFile = false }) {
144160
boundaryKey = null;
145161
compilerOutput = Completer<CompilerOutput>();
146162
_suppressCompilerMessages = suppressCompilerMessages;
147163
_expectSources = expectSources;
164+
_readFile = readFile;
148165
state = StdoutState.CollectDiagnostic;
149166
}
150167
}
@@ -191,7 +208,7 @@ class KernelCompiler {
191208
_processManager = processManager,
192209
_fileSystemScheme = fileSystemScheme,
193210
_fileSystemRoots = fileSystemRoots,
194-
_stdoutHandler = stdoutHandler ?? StdoutHandler(logger: logger);
211+
_stdoutHandler = stdoutHandler ?? StdoutHandler(logger: logger, fileSystem: fileSystem);
195212

196213
final FileSystem _fileSystem;
197214
final Artifacts _artifacts;
@@ -430,6 +447,7 @@ abstract class ResidentCompiler {
430447
@required ProcessManager processManager,
431448
@required Artifacts artifacts,
432449
@required Platform platform,
450+
@required FileSystem fileSystem,
433451
bool testCompilation,
434452
bool trackWidgetCreation,
435453
String packagesPath,
@@ -530,6 +548,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
530548
@required ProcessManager processManager,
531549
@required Artifacts artifacts,
532550
@required Platform platform,
551+
@required FileSystem fileSystem,
533552
this.testCompilation = false,
534553
this.trackWidgetCreation = true,
535554
this.packagesPath,
@@ -547,7 +566,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
547566
_logger = logger,
548567
_processManager = processManager,
549568
_artifacts = artifacts,
550-
_stdoutHandler = stdoutHandler ?? StdoutHandler(logger: logger),
569+
_stdoutHandler = stdoutHandler ?? StdoutHandler(logger: logger, fileSystem: fileSystem),
551570
_platform = platform,
552571
dartDefines = dartDefines ?? const <String>[],
553572
// This is a URI, not a file path, so the forward slash is correct even on Windows.
@@ -762,21 +781,20 @@ class DefaultResidentCompiler implements ResidentCompiler {
762781
String libraryUri,
763782
String klass,
764783
bool isStatic,
765-
) {
784+
) async {
766785
if (!_controller.hasListener) {
767786
_controller.stream.listen(_handleCompilationRequest);
768787
}
769788

770789
final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
771-
_controller.add(
772-
_CompileExpressionRequest(
773-
completer, expression, definitions, typeDefinitions, libraryUri, klass, isStatic)
774-
);
790+
final _CompileExpressionRequest request = _CompileExpressionRequest(
791+
completer, expression, definitions, typeDefinitions, libraryUri, klass, isStatic);
792+
_controller.add(request);
775793
return completer.future;
776794
}
777795

778796
Future<CompilerOutput> _compileExpression(_CompileExpressionRequest request) async {
779-
_stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false);
797+
_stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false, readFile: true);
780798

781799
// 'compile-expression' should be invoked after compiler has been started,
782800
// program was compiled.

packages/flutter_tools/lib/src/resident_runner.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class FlutterDevice {
6969
processManager: globals.processManager,
7070
logger: globals.logger,
7171
platform: globals.platform,
72+
fileSystem: globals.fs,
7273
);
7374

7475
/// Create a [FlutterDevice] with optional code generation enabled.
@@ -138,6 +139,7 @@ class FlutterDevice {
138139
artifacts: globals.artifacts,
139140
processManager: globals.processManager,
140141
logger: globals.logger,
142+
fileSystem: globals.fs,
141143
platform: platform,
142144
);
143145
} else {
@@ -173,6 +175,7 @@ class FlutterDevice {
173175
processManager: globals.processManager,
174176
logger: globals.logger,
175177
platform: platform,
178+
fileSystem: globals.fs,
176179
);
177180
}
178181

packages/flutter_tools/lib/src/run_hot.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ class HotRunner extends ResidentRunner {
165165
final CompilerOutput compilerOutput =
166166
await device.generator.compileExpression(expression, definitions,
167167
typeDefinitions, libraryUri, klass, isStatic);
168-
if (compilerOutput != null && compilerOutput.outputFilename != null) {
169-
return base64.encode(globals.fs.file(compilerOutput.outputFilename).readAsBytesSync());
168+
if (compilerOutput != null && compilerOutput.expressionData != null) {
169+
return base64.encode(compilerOutput.expressionData);
170170
}
171171
}
172172
}

packages/flutter_tools/lib/src/test/flutter_platform.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ class FlutterPlatform extends PlatformPlugin {
328328
final CompilerOutput compilerOutput =
329329
await compiler.compiler.compileExpression(expression, definitions,
330330
typeDefinitions, libraryUri, klass, isStatic);
331-
if (compilerOutput != null && compilerOutput.outputFilename != null) {
332-
return base64.encode(globals.fs.file(compilerOutput.outputFilename).readAsBytesSync());
331+
if (compilerOutput != null && compilerOutput.expressionData != null) {
332+
return base64.encode(compilerOutput.expressionData);
333333
}
334334
throw 'Failed to compile $expression';
335335
}

packages/flutter_tools/lib/src/test/test_compiler.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class TestCompiler {
111111
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
112112
platform: globals.platform,
113113
testCompilation: true,
114+
fileSystem: globals.fs,
114115
);
115116
return residentCompiler;
116117
}

packages/flutter_tools/lib/src/test/web_test_compiler.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class WebTestCompiler {
130130
processManager: _processManager,
131131
logger: _logger,
132132
platform: _platform,
133+
fileSystem: _fileSystem,
133134
);
134135

135136
final CompilerOutput output = await residentCompiler.recompile(

packages/flutter_tools/test/general.shard/compile_batch_test.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import '../src/context.dart';
1919
void main() {
2020
testWithoutContext('StdoutHandler can parse output for successful batch compilation', () async {
2121
final BufferLogger logger = BufferLogger.test();
22-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
22+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
2323

2424
stdoutHandler.reset();
2525
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'.split('\n').forEach(stdoutHandler.handler);
@@ -31,7 +31,7 @@ void main() {
3131

3232
testWithoutContext('StdoutHandler can parse output for failed batch compilation', () async {
3333
final BufferLogger logger = BufferLogger.test();
34-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
34+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
3535

3636
stdoutHandler.reset();
3737
'result abc\nline1\nline2\nabc\nabc'.split('\n').forEach(stdoutHandler.handler);
@@ -43,7 +43,7 @@ void main() {
4343

4444
testWithoutContext('KernelCompiler passes correct configuration to frontend server process', () async {
4545
final BufferLogger logger = BufferLogger.test();
46-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
46+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
4747
final Completer<void> completer = Completer<void>();
4848

4949
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -88,7 +88,7 @@ void main() {
8888

8989
testWithoutContext('KernelCompiler returns null if StdoutHandler returns null', () async {
9090
final BufferLogger logger = BufferLogger.test();
91-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
91+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
9292
final Completer<void> completer = Completer<void>();
9393

9494
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -133,7 +133,7 @@ void main() {
133133

134134
testWithoutContext('KernelCompiler returns null if frontend_server process exits with non-zero code', () async {
135135
final BufferLogger logger = BufferLogger.test();
136-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
136+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
137137
final Completer<void> completer = Completer<void>();
138138

139139
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -178,7 +178,7 @@ void main() {
178178

179179
testWithoutContext('KernelCompiler passes correct AOT config to frontend_server in aot/profile mode', () async {
180180
final BufferLogger logger = BufferLogger.test();
181-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
181+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
182182
final Completer<void> completer = Completer<void>();
183183

184184
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -225,7 +225,7 @@ void main() {
225225

226226
testWithoutContext('passes correct AOT config to kernel compiler in aot/release mode', () async {
227227
final BufferLogger logger = BufferLogger.test();
228-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
228+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
229229
final Completer<void> completer = Completer<void>();
230230

231231
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -272,7 +272,7 @@ void main() {
272272

273273
testWithoutContext('KernelCompiler passes dartDefines to the frontend_server', () async {
274274
final BufferLogger logger = BufferLogger.test();
275-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
275+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
276276
final Completer<void> completer = Completer<void>();
277277

278278
final KernelCompiler kernelCompiler = KernelCompiler(
@@ -321,7 +321,7 @@ void main() {
321321

322322
testWithoutContext('KernelCompiler maps a file to a multi-root scheme if provided', () async {
323323
final BufferLogger logger = BufferLogger.test();
324-
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger);
324+
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
325325
final Completer<void> completer = Completer<void>();
326326

327327
final KernelCompiler kernelCompiler = KernelCompiler(

packages/flutter_tools/test/general.shard/compile_expression_test.dart

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import 'dart:async';
88

9+
import 'package:file/memory.dart';
910
import 'package:flutter_tools/src/artifacts.dart';
1011
import 'package:flutter_tools/src/base/common.dart';
1112
import 'package:flutter_tools/src/base/io.dart';
@@ -30,20 +31,23 @@ void main() {
3031
MockStream mockFrontendServerStdErr;
3132
StreamController<String> stdErrStreamController;
3233
BufferLogger testLogger;
34+
MemoryFileSystem fileSystem;
3335

3436
setUp(() {
3537
testLogger = BufferLogger.test();
3638
mockProcessManager = MockProcessManager();
3739
mockFrontendServer = MockProcess();
3840
mockFrontendServerStdIn = MockStdIn();
3941
mockFrontendServerStdErr = MockStream();
42+
fileSystem = MemoryFileSystem.test();
4043
generator = ResidentCompiler(
4144
'sdkroot',
4245
buildMode: BuildMode.debug,
4346
artifacts: Artifacts.test(),
4447
processManager: mockProcessManager,
4548
logger: testLogger,
4649
platform: FakePlatform(operatingSystem: 'linux'),
50+
fileSystem: fileSystem,
4751
);
4852

4953
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
@@ -75,6 +79,9 @@ void main() {
7579
Completer<List<int>>();
7680
final Completer<List<int>> compileExpressionResponseCompleter =
7781
Completer<List<int>>();
82+
fileSystem.file('/path/to/main.dart.dill')
83+
..createSync(recursive: true)
84+
..writeAsBytesSync(<int>[1, 2, 3, 4]);
7885

7986
when(mockFrontendServer.stdout)
8087
.thenAnswer((Invocation invocation) =>
@@ -108,8 +115,7 @@ void main() {
108115
'2+2', null, null, null, null, false).then(
109116
(CompilerOutput outputExpression) {
110117
expect(outputExpression, isNotNull);
111-
expect(outputExpression.outputFilename, equals('/path/to/main.dart.dill.incremental'));
112-
expect(outputExpression.errorCount, 0);
118+
expect(outputExpression.expressionData, <int>[1, 2, 3, 4]);
113119
}
114120
);
115121
});
@@ -141,6 +147,9 @@ void main() {
141147
equals('line1\nline2\n'));
142148
expect(outputCompile.outputFilename, equals('/path/to/main.dart.dill'));
143149

150+
fileSystem.file('/path/to/main.dart.dill.incremental')
151+
..createSync(recursive: true)
152+
..writeAsBytesSync(<int>[0, 1, 2, 3]);
144153
compileExpressionResponseCompleter1.complete(Future<List<int>>.value(utf8.encode(
145154
'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
146155
)));
@@ -153,9 +162,11 @@ void main() {
153162
generator.compileExpression('0+1', null, null, null, null, false).then(
154163
(CompilerOutput outputExpression) {
155164
expect(outputExpression, isNotNull);
156-
expect(outputExpression.outputFilename,
157-
equals('/path/to/main.dart.dill.incremental'));
158-
expect(outputExpression.errorCount, 0);
165+
expect(outputExpression.expressionData, <int>[0, 1, 2, 3]);
166+
167+
fileSystem.file('/path/to/main.dart.dill.incremental')
168+
..createSync(recursive: true)
169+
..writeAsBytesSync(<int>[4, 5, 6, 7]);
159170
compileExpressionResponseCompleter2.complete(Future<List<int>>.value(utf8.encode(
160171
'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
161172
)));
@@ -168,9 +179,7 @@ void main() {
168179
generator.compileExpression('1+1', null, null, null, null, false).then(
169180
(CompilerOutput outputExpression) {
170181
expect(outputExpression, isNotNull);
171-
expect(outputExpression.outputFilename,
172-
equals('/path/to/main.dart.dill.incremental'));
173-
expect(outputExpression.errorCount, 0);
182+
expect(outputExpression.expressionData, <int>[4, 5, 6, 7]);
174183
lastExpressionCompleted.complete(true);
175184
},
176185
),

0 commit comments

Comments
 (0)