Skip to content

Commit 309a2d7

Browse files
authored
Extract snapshotting logic to Snapshotter class (flutter#11591)
First step in eliminating code duplication between script snapshotting (in FLX build) and AOT, assembly AOT snapshotting.
1 parent f1f5d4f commit 309a2d7

3 files changed

Lines changed: 328 additions & 74 deletions

File tree

packages/flutter_tools/lib/src/base/build.dart

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,44 @@ import 'dart:async';
66
import 'dart:convert' show JSON;
77

88
import 'package:crypto/crypto.dart' show md5;
9+
import 'package:meta/meta.dart';
910

11+
import '../artifacts.dart';
12+
import '../build_info.dart';
13+
import '../globals.dart';
14+
import 'context.dart';
1015
import 'file_system.dart';
16+
import 'process.dart';
17+
18+
GenSnapshot get genSnapshot => context.putIfAbsent(GenSnapshot, () => const GenSnapshot());
19+
20+
class GenSnapshot {
21+
const GenSnapshot();
22+
23+
Future<int> run({
24+
@required TargetPlatform targetPlatform,
25+
@required BuildMode buildMode,
26+
@required String packagesPath,
27+
@required String depfilePath,
28+
Iterable<String> additionalArgs: const <String>[],
29+
}) {
30+
final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData);
31+
final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData);
32+
final List<String> args = <String>[
33+
'--assert_initializer',
34+
'--await_is_keyword',
35+
'--causal_async_stacks',
36+
'--vm_snapshot_data=$vmSnapshotData',
37+
'--isolate_snapshot_data=$isolateSnapshotData',
38+
'--packages=$packagesPath',
39+
'--dependencies=$depfilePath',
40+
'--print_snapshot_sizes',
41+
]..addAll(additionalArgs);
42+
43+
final String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot, targetPlatform, buildMode);
44+
return runCommandAndStreamOutput(<String>[snapshotterPath]..addAll(args));
45+
}
46+
}
1147

1248
/// A collection of checksums for a set of input files.
1349
///
@@ -68,3 +104,109 @@ Future<Set<String>> readDepfile(String depfilePath) async {
68104
.where((String path) => path.isNotEmpty)
69105
.toSet();
70106
}
107+
108+
/// Dart snapshot builder.
109+
///
110+
/// Builds Dart snapshots in one of three modes:
111+
/// * Script snapshot: architecture-independent snapshot of a Dart script core
112+
/// libraries.
113+
/// * AOT snapshot: architecture-specific ahead-of-time compiled snapshot
114+
/// suitable for loading with `mmap`.
115+
/// * Assembly AOT snapshot: architecture-specific ahead-of-time compile to
116+
/// assembly suitable for compilation as a static or dynamic library.
117+
class Snapshotter {
118+
/// Builds an architecture-independent snapshot of the specified script.
119+
Future<int> buildScriptSnapshot({
120+
@required String mainPath,
121+
@required String snapshotPath,
122+
@required String depfilePath,
123+
@required String packagesPath
124+
}) async {
125+
final List<String> args = <String>[
126+
'--snapshot_kind=script',
127+
'--script_snapshot=$snapshotPath',
128+
mainPath,
129+
];
130+
131+
final String checksumsPath = '$depfilePath.checksums';
132+
final int exitCode = await _build(
133+
outputSnapshotPath: snapshotPath,
134+
packagesPath: packagesPath,
135+
snapshotArgs: args,
136+
depfilePath: depfilePath,
137+
mainPath: mainPath,
138+
checksumsPath: checksumsPath,
139+
);
140+
if (exitCode != 0)
141+
return exitCode;
142+
await _writeChecksum(snapshotPath, depfilePath, mainPath, checksumsPath);
143+
return exitCode;
144+
}
145+
146+
/// Builds an architecture-specific ahead-of-time compiled snapshot of the specified script.
147+
Future<Null> buildAotSnapshot() async {
148+
throw new UnimplementedError('AOT snapshotting not yet implemented');
149+
}
150+
151+
Future<int> _build({
152+
@required List<String> snapshotArgs,
153+
@required String outputSnapshotPath,
154+
@required String packagesPath,
155+
@required String depfilePath,
156+
@required String mainPath,
157+
@required String checksumsPath,
158+
}) async {
159+
if (!await _isBuildRequired(outputSnapshotPath, depfilePath, mainPath, checksumsPath)) {
160+
printTrace('Skipping snapshot build. Checksums match.');
161+
return 0;
162+
}
163+
164+
// Build the snapshot.
165+
final int exitCode = await genSnapshot.run(
166+
targetPlatform: null,
167+
buildMode: BuildMode.debug,
168+
packagesPath: packagesPath,
169+
depfilePath: depfilePath,
170+
additionalArgs: snapshotArgs,
171+
);
172+
if (exitCode != 0)
173+
return exitCode;
174+
175+
_writeChecksum(outputSnapshotPath, depfilePath, mainPath, checksumsPath);
176+
return 0;
177+
}
178+
179+
Future<bool> _isBuildRequired(String outputSnapshotPath, String depfilePath, String mainPath, String checksumsPath) async {
180+
final File checksumFile = fs.file(checksumsPath);
181+
final File outputSnapshotFile = fs.file(outputSnapshotPath);
182+
final File depfile = fs.file(depfilePath);
183+
if (!outputSnapshotFile.existsSync() || !depfile.existsSync() || !checksumFile.existsSync())
184+
return true;
185+
186+
try {
187+
if (checksumFile.existsSync()) {
188+
final Checksum oldChecksum = new Checksum.fromJson(await checksumFile.readAsString());
189+
final Set<String> checksumPaths = await readDepfile(depfilePath)
190+
..addAll(<String>[outputSnapshotPath, mainPath]);
191+
final Checksum newChecksum = new Checksum.fromFiles(checksumPaths);
192+
return oldChecksum != newChecksum;
193+
}
194+
} catch (e, s) {
195+
// Log exception and continue, this step is a performance improvement only.
196+
printTrace('Error during snapshot checksum output: $e\n$s');
197+
}
198+
return true;
199+
}
200+
201+
Future<Null> _writeChecksum(String outputSnapshotPath, String depfilePath, String mainPath, String checksumsPath) async {
202+
try {
203+
final Set<String> checksumPaths = await readDepfile(depfilePath)
204+
..addAll(<String>[outputSnapshotPath, mainPath]);
205+
final Checksum checksum = new Checksum.fromFiles(checksumPaths);
206+
await fs.file(checksumsPath).writeAsString(checksum.toJson());
207+
} catch (e, s) {
208+
// Log exception and continue, this step is a performance improvement only.
209+
print('Error during snapshot checksum output: $e\n$s');
210+
}
211+
}
212+
}

packages/flutter_tools/lib/src/flx.dart

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@
44

55
import 'dart:async';
66

7-
import 'package:meta/meta.dart' show required;
8-
9-
import 'artifacts.dart';
107
import 'asset.dart';
118
import 'base/build.dart';
129
import 'base/common.dart';
1310
import 'base/file_system.dart';
14-
import 'base/process.dart';
1511
import 'build_info.dart';
1612
import 'dart/package_map.dart';
1713
import 'devfs.dart';
@@ -30,74 +26,6 @@ const String _kKernelKey = 'kernel_blob.bin';
3026
const String _kSnapshotKey = 'snapshot_blob.bin';
3127
const String _kDylibKey = 'libapp.so';
3228

33-
Future<int> _createSnapshot({
34-
@required String mainPath,
35-
@required String snapshotPath,
36-
@required String depfilePath,
37-
@required String packages
38-
}) async {
39-
assert(mainPath != null);
40-
assert(snapshotPath != null);
41-
assert(depfilePath != null);
42-
assert(packages != null);
43-
final String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot, null, BuildMode.debug);
44-
final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData);
45-
final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData);
46-
47-
final List<String> args = <String>[
48-
snapshotterPath,
49-
'--snapshot_kind=script',
50-
'--vm_snapshot_data=$vmSnapshotData',
51-
'--isolate_snapshot_data=$isolateSnapshotData',
52-
'--packages=$packages',
53-
'--script_snapshot=$snapshotPath',
54-
'--dependencies=$depfilePath',
55-
mainPath,
56-
];
57-
58-
// Write the depfile path to disk.
59-
fs.file(depfilePath).parent.childFile('gen_snapshot.d').writeAsString('$depfilePath: $snapshotterPath\n');
60-
61-
final File checksumFile = fs.file('$depfilePath.checksums');
62-
final File snapshotFile = fs.file(snapshotPath);
63-
final File depfile = fs.file(depfilePath);
64-
if (snapshotFile.existsSync() && depfile.existsSync() && checksumFile.existsSync()) {
65-
try {
66-
final String json = await checksumFile.readAsString();
67-
final Checksum oldChecksum = new Checksum.fromJson(json);
68-
final Set<String> inputPaths = await readDepfile(depfilePath);
69-
inputPaths.add(snapshotPath);
70-
inputPaths.add(mainPath);
71-
final Checksum newChecksum = new Checksum.fromFiles(inputPaths);
72-
if (oldChecksum == newChecksum) {
73-
printTrace('Skipping snapshot build. Checksums match.');
74-
return 0;
75-
}
76-
} catch (e, s) {
77-
// Log exception and continue, this step is a performance improvement only.
78-
printTrace('Error during snapshot checksum check: $e\n$s');
79-
}
80-
}
81-
82-
// Build the snapshot.
83-
final int exitCode = await runCommandAndStreamOutput(args);
84-
if (exitCode != 0)
85-
return exitCode;
86-
87-
// Compute and record input file checksums.
88-
try {
89-
final Set<String> inputPaths = await readDepfile(depfilePath);
90-
inputPaths.add(snapshotPath);
91-
inputPaths.add(mainPath);
92-
final Checksum checksum = new Checksum.fromFiles(inputPaths);
93-
await checksumFile.writeAsString(checksum.toJson());
94-
} catch (e, s) {
95-
// Log exception and continue, this step is a performance improvement only.
96-
printTrace('Error during snapshot checksum output: $e\n$s');
97-
}
98-
return 0;
99-
}
100-
10129
Future<Null> build({
10230
String mainPath: defaultMainPath,
10331
String manifestPath: defaultManifestPath,
@@ -123,11 +51,12 @@ Future<Null> build({
12351

12452
// In a precompiled snapshot, the instruction buffer contains script
12553
// content equivalents
126-
final int result = await _createSnapshot(
54+
final Snapshotter snapshotter = new Snapshotter();
55+
final int result = await snapshotter.buildScriptSnapshot(
12756
mainPath: mainPath,
12857
snapshotPath: snapshotPath,
12958
depfilePath: depfilePath,
130-
packages: packagesPath
59+
packagesPath: packagesPath,
13160
);
13261
if (result != 0)
13362
throwToolExit('Failed to run the Flutter compiler. Exit code: $result', exitCode: result);

0 commit comments

Comments
 (0)