Skip to content

Commit 0ce6724

Browse files
derekxu16Commit Queue
authored andcommitted
[ResidentFrontendServer] Add 'replaceCachedDill' endpoint
TEST=test case added to `pkg/frontend_server/test/src/resident_frontend_server_test.dart` Change-Id: I45a4b28c8c89714dcb93fa7f64874e158a0d69df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394763 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Derek Xu <[email protected]>
1 parent e1faaad commit 0ce6724

File tree

4 files changed

+156
-6
lines changed

4 files changed

+156
-6
lines changed

pkg/dartdev/lib/src/commands/run.dart

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import 'dart:io';
88
import 'package:args/args.dart';
99
import 'package:front_end/src/api_prototype/compiler_options.dart'
1010
show Verbosity;
11+
import 'package:frontend_server/resident_frontend_server_utils.dart'
12+
show invokeReplaceCachedDill;
1113
import 'package:path/path.dart';
1214
import 'package:pub/pub.dart';
1315

@@ -428,8 +430,26 @@ class RunCommand extends DartdevCommand {
428430
}
429431

430432
final executableFile = File(executable.executable);
431-
if (!await isFileKernelFile(executableFile) &&
432-
!await isFileAppJitSnapshot(executableFile) &&
433+
if (await isFileKernelFile(executableFile)) {
434+
// If the file is a kernel file, we do not need to compile it, but we do
435+
// need to replace the file in the resident frontend compiler kernel
436+
// cache associated with this executable, because the cached kernel file
437+
// may be used to populate context for expression evaluation later.
438+
await ensureCompilationServerIsRunning(residentCompilerInfoFile);
439+
final succeeded = await invokeReplaceCachedDill(
440+
replacementDillPath: executableFile.absolute.path,
441+
serverInfoFile: residentCompilerInfoFile,
442+
);
443+
if (!succeeded) {
444+
log.stderr(
445+
'Error: Encountered a problem accessing the Resident Frontend '
446+
"Compiler's kernel file cache. Please try re-running the same "
447+
'command again. If the error persists, please file an issue at '
448+
'https://github.com/dart-lang/sdk/issues/new.',
449+
);
450+
return errorExitCode;
451+
}
452+
} else if (!await isFileAppJitSnapshot(executableFile) &&
433453
!await isFileAotSnapshot(executableFile)) {
434454
final compiledKernelFile = await _compileToKernelUsingResidentCompiler(
435455
executable: executable,

pkg/frontend_server/lib/resident_frontend_server_utils.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:convert' show jsonDecode;
5+
import 'dart:convert' show jsonDecode, jsonEncode;
66
import 'dart:io' show Directory, File, InternetAddress, Socket;
77

88
import 'package:path/path.dart' as path;
@@ -112,3 +112,22 @@ Future<Map<String, dynamic>> sendAndReceiveResponse(
112112
client?.destroy();
113113
return jsonResponse;
114114
}
115+
116+
/// Sends a 'replaceCachedDill' request with [replacementDillPath] as the lone
117+
/// argument to the resident frontend compiler associated with [serverInfoFile],
118+
/// and returns a boolean indicating whether or not replacement succeeded.
119+
///
120+
/// Throws a [FileSystemException] if [serverInfoFile] cannot be accessed.
121+
Future<bool> invokeReplaceCachedDill({
122+
required String replacementDillPath,
123+
required File serverInfoFile,
124+
}) async {
125+
final Map<String, dynamic> response = await sendAndReceiveResponse(
126+
jsonEncode({
127+
'command': 'replaceCachedDill',
128+
'replacementDillPath': replacementDillPath,
129+
}),
130+
serverInfoFile,
131+
);
132+
return response['success'];
133+
}

pkg/frontend_server/lib/src/resident_frontend_server.dart

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'dart:typed_data' show Uint8List;
1818
import 'package:args/args.dart';
1919
import 'package:front_end/src/api_unstable/vm.dart';
2020
import 'package:kernel/binary/tag.dart' show expectedSdkHash;
21+
import 'package:kernel/kernel.dart' show Component, loadComponentFromBytes;
2122
import 'package:path/path.dart' as path;
2223

2324
import '../frontend_server.dart';
@@ -89,6 +90,10 @@ class ResidentCompiler {
8990
updateState(_compileOptions);
9091
}
9192

93+
void resetStateToWaitingForFirstCompile() {
94+
_state = _ResidentState.waitingForFirstCompile;
95+
}
96+
9297
/// The [ResidentCompiler] will use the [newOptions] for future compilation
9398
/// requests.
9499
void updateState(ArgResults newOptions) {
@@ -99,7 +104,7 @@ class ResidentCompiler {
99104
// Refresh the compiler's output for the next compile
100105
_compilerOutput.clear();
101106
_formattedOutput.clear();
102-
_state = _ResidentState.waitingForFirstCompile;
107+
resetStateToWaitingForFirstCompile();
103108
}
104109

105110
/// The current compiler options are outdated when any option has changed
@@ -170,7 +175,7 @@ class ResidentCompiler {
170175
..resetIncrementalCompiler();
171176
_state = _ResidentState.waitingForRecompile;
172177
} else {
173-
_state = _ResidentState.waitingForFirstCompile;
178+
resetStateToWaitingForFirstCompile();
174179
}
175180

176181
return _createResponseMap(
@@ -256,6 +261,8 @@ class ResidentCompiler {
256261
/// residentListenAndCompile method.
257262
class ResidentFrontendServer {
258263
static const String _commandString = 'command';
264+
static const String _replaceCachedDillString = 'replaceCachedDill';
265+
static const String _replacementDillPathString = 'replacementDillPath';
259266
static const String _compileString = 'compile';
260267
static const String _executableString = 'executable';
261268
static const String _packageString = 'packages';
@@ -301,6 +308,43 @@ class ResidentFrontendServer {
301308
return residentCompiler;
302309
}
303310

311+
static Future<String> _handleReplaceCachedDillRequest(
312+
Map<String, dynamic> request,
313+
) async {
314+
if (request[_replacementDillPathString] == null) {
315+
return _encodeErrorMessage(
316+
"'$_replaceCachedDillString' requests must include a "
317+
"'$_replacementDillPathString' property.",
318+
);
319+
}
320+
321+
final File replacementDillFile =
322+
new File(request[_replacementDillPathString]);
323+
324+
final String canonicalizedLibraryPath;
325+
try {
326+
final Component component =
327+
loadComponentFromBytes(replacementDillFile.readAsBytesSync());
328+
canonicalizedLibraryPath = path.canonicalize(
329+
component.mainMethod!.enclosingLibrary.fileUri.toFilePath(),
330+
);
331+
332+
final String cachedDillPath =
333+
computeCachedDillPath(canonicalizedLibraryPath);
334+
replacementDillFile.copySync(cachedDillPath);
335+
} catch (e) {
336+
return _encodeErrorMessage('Failed to replace cached dill');
337+
}
338+
339+
if (compilers[canonicalizedLibraryPath] != null) {
340+
compilers[canonicalizedLibraryPath]!.resetStateToWaitingForFirstCompile();
341+
}
342+
343+
return jsonEncode({
344+
"success": true,
345+
});
346+
}
347+
304348
static Future<String> _handleCompileRequest(
305349
Map<String, dynamic> request,
306350
) async {
@@ -365,6 +409,8 @@ class ResidentFrontendServer {
365409
}
366410

367411
switch (request[_commandString]) {
412+
case _replaceCachedDillString:
413+
return _handleReplaceCachedDillRequest(request);
368414
case _compileString:
369415
return _handleCompileRequest(request);
370416
case _shutdownString:

pkg/frontend_server/test/src/resident_frontend_server_test.dart

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,72 @@ void main() async {
103103
});
104104
});
105105

106-
group('Resident Frontend Server: compile tests: ', () {
106+
group("Resident Frontend Server: 'replaceCachedDill' command tests: ", () {
107+
late Directory d;
108+
late File executable, outputDill;
109+
110+
setUp(() async {
111+
d = Directory.systemTemp.createTempSync();
112+
executable = new File(path.join(d.path, 'src.dart'))
113+
..createSync()
114+
..writeAsStringSync('void main() {print("hello " "there");}');
115+
outputDill = new File(path.join(d.path, 'src.dart.dill'));
116+
});
117+
118+
tearDown(() async {
119+
d.deleteSync(recursive: true);
120+
ResidentFrontendServer.compilers.clear();
121+
});
122+
123+
test('basic', () async {
124+
final File cachedDillFile =
125+
new File(computeCachedDillPath(executable.path));
126+
expect(cachedDillFile.existsSync(), false);
127+
128+
final Map<String, dynamic> compileResult =
129+
jsonDecode(await ResidentFrontendServer.handleRequest(
130+
ResidentFrontendServer.createCompileJSON(
131+
executable: executable.path,
132+
outputDill: outputDill.path,
133+
),
134+
));
135+
expect(compileResult['success'], true);
136+
137+
expect(cachedDillFile.existsSync(), true);
138+
// Delete the kernel file associated with [executable.path] from the
139+
// resident frontend compiler kernel cache.
140+
cachedDillFile.deleteSync();
141+
142+
final Map<String, dynamic> replaceCachedDillResult = jsonDecode(
143+
await ResidentFrontendServer.handleRequest(
144+
jsonEncode({
145+
'command': 'replaceCachedDill',
146+
'replacementDillPath': outputDill.path,
147+
}),
148+
),
149+
);
150+
expect(replaceCachedDillResult['success'], true);
151+
// Calling 'replaceCachedDill' with [outputDill] as the replacement dill
152+
// should make [outputDill] the kernel file associated with
153+
// [executable.path] in the resident frontend compiler kernel cache.
154+
expect(cachedDillFile.existsSync(), true);
155+
cachedDillFile.deleteSync();
156+
});
157+
158+
test("invalid 'replacementDillPath' property in request", () async {
159+
final Map<String, dynamic> replaceCachedDillResult = jsonDecode(
160+
await ResidentFrontendServer.handleRequest(
161+
jsonEncode({
162+
'command': 'replaceCachedDill',
163+
'replacementDillPath': path.join(d.path, 'nonexistent'),
164+
}),
165+
),
166+
);
167+
expect(replaceCachedDillResult['success'], false);
168+
});
169+
});
170+
171+
group("Resident Frontend Server: 'compile' command tests: ", () {
107172
late Directory d;
108173
late File executable, package, outputDill;
109174

0 commit comments

Comments
 (0)