Improve AOT snapshot input verification + cleanup (#17144)
Bugfix: Moves AOT snapshot input verification past where the last input
is added to the inputs list.
Cleanup:
* Extracts _isValidAotPlatform method.
* Moves non-platform-specific logic to the top.
* Moves variable declaration closer to first use, and inlines to a
narrower scope where possible.
This relands #17136, which was reverted in #17142 due to breakage in
on-device iOS debug builds.
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index 0f32839..3a2f609 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -264,36 +264,16 @@
@required bool preferSharedLibrary,
List<String> extraGenSnapshotOptions: const <String>[],
}) async {
- if (!(platform == TargetPlatform.android_arm ||
- platform == TargetPlatform.android_arm64 ||
- platform == TargetPlatform.ios)) {
+ if (!_isValidAotPlatform(platform)) {
printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
return -2;
}
- final Directory outputDir = fs.directory(outputPath);
- outputDir.createSync(recursive: true);
-
- final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
- final String isolateSnapshotData = fs.path.join(outputDir.path, 'isolate_snapshot_data');
- final String depfilePath = fs.path.join(outputDir.path, 'snapshot.d');
- final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S');
- final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o');
- final String assemblySo = fs.path.join(outputDir.path, 'app.so');
- final bool compileToSharedLibrary =
- preferSharedLibrary && androidSdk.ndkCompiler != null;
-
+ final bool compileToSharedLibrary = preferSharedLibrary && androidSdk.ndkCompiler != null;
if (preferSharedLibrary && !compileToSharedLibrary) {
- printStatus(
- 'Could not find NDK compiler. Not building in shared library mode');
+ printStatus('Could not find NDK compiler. Not building in shared library mode.');
}
- final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
- assert(vmEntryPoints != null);
-
- final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
- assert(ioEntryPoints != null);
-
final PackageMap packageMap = new PackageMap(packagesPath);
final String packageMapError = packageMap.checkValid();
if (packageMapError != null) {
@@ -301,19 +281,19 @@
return -3;
}
+ final Directory outputDir = fs.directory(outputPath);
+ outputDir.createSync(recursive: true);
+
final String skyEnginePkg = _getPackagePath(packageMap, 'sky_engine');
final String uiPath = fs.path.join(skyEnginePkg, 'lib', 'ui', 'ui.dart');
final String vmServicePath = fs.path.join(skyEnginePkg, 'sdk_ext', 'vmservice_io.dart');
- final List<String> inputPaths = <String>[vmEntryPoints, ioEntryPoints, uiPath, vmServicePath, mainPath];
+ final List<String> inputPaths = <String>[uiPath, vmServicePath, mainPath];
final Set<String> outputPaths = new Set<String>();
- final Iterable<String> missingInputs = inputPaths.where((String p) => !fs.isFileSync(p));
- if (missingInputs.isNotEmpty) {
- printError('Missing input files: $missingInputs');
- return -4;
- }
-
+ final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
+ final String isolateSnapshotData = fs.path.join(outputDir.path, 'isolate_snapshot_data');
+ final String depfilePath = fs.path.join(outputDir.path, 'snapshot.d');
final List<String> genSnapshotArgs = <String>[
'--vm_snapshot_data=$vmSnapshotData',
'--isolate_snapshot_data=$isolateSnapshotData',
@@ -321,42 +301,56 @@
'--url_mapping=dart:vmservice_io,$vmServicePath',
'--dependencies=$depfilePath',
];
-
- if ((extraGenSnapshotOptions != null) && extraGenSnapshotOptions.isNotEmpty) {
- printTrace('Extra gen-snapshot options: $extraGenSnapshotOptions');
+ if (previewDart2) {
+ genSnapshotArgs.addAll(<String>[
+ '--reify-generic-functions',
+ '--strong',
+ ]);
+ }
+ if (buildMode != BuildMode.release) {
+ genSnapshotArgs.addAll(<String>[
+ '--no-checked',
+ '--conditional_directives',
+ ]);
+ }
+ if (extraGenSnapshotOptions != null && extraGenSnapshotOptions.isNotEmpty) {
+ printTrace('Extra gen_snapshot options: $extraGenSnapshotOptions');
genSnapshotArgs.addAll(extraGenSnapshotOptions);
}
final bool interpreter = _isInterpreted(platform, buildMode);
if (!interpreter) {
+ final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
+ final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
genSnapshotArgs.add('--embedder_entry_points_manifest=$vmEntryPoints');
genSnapshotArgs.add('--embedder_entry_points_manifest=$ioEntryPoints');
+ inputPaths..addAll(<String>[vmEntryPoints, ioEntryPoints]);
}
- // iOS symbols used to load snapshot data in the engine.
+ // iOS snapshot generated files, compiled object files.
const String kVmSnapshotData = 'kDartVmSnapshotData';
const String kIsolateSnapshotData = 'kDartIsolateSnapshotData';
-
- // iOS snapshot generated files, compiled object files.
final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o');
final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o');
+ // Compile-to-assembly outputs.
+ final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S');
+ final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o');
+ final String assemblySo = fs.path.join(outputDir.path, 'app.so');
+
switch (platform) {
case TargetPlatform.android_arm:
case TargetPlatform.android_arm64:
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
- final String vmSnapshotInstructions = fs.path.join(outputDir.path, 'vm_snapshot_instr');
- final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
if (compileToSharedLibrary) {
outputPaths.add(assemblySo);
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
genSnapshotArgs.add('--assembly=$assembly');
} else {
- outputPaths.addAll(<String>[
- vmSnapshotData,
- isolateSnapshotData,
- ]);
+ final String vmSnapshotInstructions = fs.path.join(outputDir.path, 'vm_snapshot_instr');
+ final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
+ outputPaths.addAll(<String>[vmSnapshotData, isolateSnapshotData]);
genSnapshotArgs.addAll(<String>[
'--snapshot_kind=app-aot-blobs',
'--vm_snapshot_instructions=$vmSnapshotInstructions',
@@ -371,15 +365,9 @@
}
break;
case TargetPlatform.ios:
- final String snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode);
- inputPaths.add(snapshotDartIOS);
if (interpreter) {
genSnapshotArgs.add('--snapshot_kind=core');
- genSnapshotArgs.add(snapshotDartIOS);
- outputPaths.addAll(<String>[
- kVmSnapshotDataO,
- kIsolateSnapshotDataO,
- ]);
+ outputPaths.addAll(<String>[kVmSnapshotDataO, kIsolateSnapshotDataO]);
} else {
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
genSnapshotArgs.add('--assembly=$assembly');
@@ -394,13 +382,22 @@
assert(false);
}
- if (buildMode != BuildMode.release) {
- genSnapshotArgs.addAll(<String>[
- '--no-checked',
- '--conditional_directives',
- ]);
+ if (interpreter) {
+ final String snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode);
+ inputPaths.add(snapshotDartIOS);
+ genSnapshotArgs.add(snapshotDartIOS);
+ } else {
+ genSnapshotArgs.add(mainPath);
}
+ // Verify that all required inputs exist.
+ final Iterable<String> missingInputs = inputPaths.where((String p) => !fs.isFileSync(p));
+ if (missingInputs.isNotEmpty) {
+ printError('Missing input files: $missingInputs from $inputPaths');
+ return -4;
+ }
+
+ // If inputs and outputs have not changed since last run, skip the build.
final String fingerprintPath = '$depfilePath.fingerprint';
final SnapshotType snapshotType = new SnapshotType(platform, buildMode);
if (!await _isBuildRequired(snapshotType, outputPaths, depfilePath, mainPath, fingerprintPath)) {
@@ -408,14 +405,6 @@
return 0;
}
- if (previewDart2) {
- genSnapshotArgs.addAll(<String>[
- '--reify-generic-functions',
- '--strong',
- ]);
- }
- genSnapshotArgs.add(mainPath);
-
final int genSnapshotExitCode = await genSnapshot.run(
snapshotType: new SnapshotType(platform, buildMode),
packagesPath: packageMap.packagesPath,
@@ -436,12 +425,10 @@
if (platform == TargetPlatform.ios) {
printStatus('Building App.framework...');
- final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c');
- final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c');
-
const List<String> commonBuildOptions = const <String>['-arch', 'arm64', '-miphoneos-version-min=8.0'];
-
if (interpreter) {
+ final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c');
+ final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c');
await fs.file(vmSnapshotData).rename(fs.path.join(outputDir.path, kVmSnapshotData));
await fs.file(isolateSnapshotData).rename(fs.path.join(outputDir.path, kIsolateSnapshotData));
@@ -497,6 +484,14 @@
return 0;
}
+ bool _isValidAotPlatform(TargetPlatform platform) {
+ return const <TargetPlatform>[
+ TargetPlatform.android_arm,
+ TargetPlatform.android_arm64,
+ TargetPlatform.ios,
+ ].contains(platform);
+ }
+
/// Returns true if the specified platform and build mode require running in interpreted mode.
bool _isInterpreted(TargetPlatform platform, BuildMode buildMode) {
return platform == TargetPlatform.ios && buildMode == BuildMode.debug;
diff --git a/packages/flutter_tools/test/base/build_test.dart b/packages/flutter_tools/test/base/build_test.dart
index ca5e764..e58c87f 100644
--- a/packages/flutter_tools/test/base/build_test.dart
+++ b/packages/flutter_tools/test/base/build_test.dart
@@ -662,13 +662,12 @@
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
- '--snapshot_kind=core',
- 'snapshot.dart',
- '--no-checked',
- '--conditional_directives',
'--reify-generic-functions',
'--strong',
- 'main.dill',
+ '--no-checked',
+ '--conditional_directives',
+ '--snapshot_kind=core',
+ 'snapshot.dart',
]);
}, overrides: contextOverrides);
@@ -704,14 +703,14 @@
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
+ '--reify-generic-functions',
+ '--strong',
+ '--no-checked',
+ '--conditional_directives',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
- '--no-checked',
- '--conditional_directives',
- '--reify-generic-functions',
- '--strong',
'main.dill',
]);
}, overrides: contextOverrides);
@@ -748,12 +747,12 @@
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
+ '--reify-generic-functions',
+ '--strong',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
- '--reify-generic-functions',
- '--strong',
'main.dill',
]);
}, overrides: contextOverrides);