[native_assets] Don't tree-shake `vm:ffi:native-assets` library
Adds a `pragma('vm:entry-point')` to the synthesized library and makes
the tree-shakers respect that pragma on `library`s.
TEST=tests/ffi/native_assets/asset_relative_test.dart
Bug: Found in g3.
Change-Id: I1bc63b42ab867a5f1d2e7f9da4842de59f3d5c1d
Cq-Include-Trybots: dart/try:vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-asan-linux-release-arm64-try,vm-msan-linux-release-arm64-try,vm-tsan-linux-release-arm64-try,vm-ubsan-linux-release-arm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/377442
Auto-Submit: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
diff --git a/pkg/vm/bin/protobuf_aware_treeshaker.dart b/pkg/vm/bin/protobuf_aware_treeshaker.dart
index e7dd01c..fa11fa7 100644
--- a/pkg/vm/bin/protobuf_aware_treeshaker.dart
+++ b/pkg/vm/bin/protobuf_aware_treeshaker.dart
@@ -182,7 +182,8 @@
return lib.classes.isEmpty &&
lib.procedures.isEmpty &&
lib.fields.isEmpty &&
- lib.typedefs.isEmpty;
+ lib.typedefs.isEmpty &&
+ lib.annotations.isEmpty;
}
bool isCoreLibrary(Library library) {
diff --git a/pkg/vm/lib/native_assets/synthesizer.dart b/pkg/vm/lib/native_assets/synthesizer.dart
index 4d8321a..75e0160 100644
--- a/pkg/vm/lib/native_assets/synthesizer.dart
+++ b/pkg/vm/lib/native_assets/synthesizer.dart
@@ -67,9 +67,13 @@
fileUri: _dummyFileUri,
annotations: [
ConstantExpression(InstanceConstant(pragmaClass.reference, [], {
+ pragmaName.fieldReference: StringConstant('vm:entry-point'),
+ pragmaOptions.fieldReference: NullConstant(),
+ })),
+ ConstantExpression(InstanceConstant(pragmaClass.reference, [], {
pragmaName.fieldReference: StringConstant('vm:ffi:native-assets'),
pragmaOptions.fieldReference: nativeAssetsConstant,
- }))
+ })),
],
);
}
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index d08b0ae..5374932 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -66,6 +66,20 @@
}
@override
+ visitLibrary(Library library) {
+ final type = _annotationsDefineRoot(library.annotations);
+ if (type != null) {
+ if (type == PragmaEntryPointType.Default) {
+ nativeCodeOracle.addLibraryReferencedFromNativeCode(library);
+ } else {
+ throw "Error: pragma entry-point definition on a library must evaluate "
+ "to null. See entry_points_pragma.md.";
+ }
+ }
+ library.visitChildren(this);
+ }
+
+ @override
visitClass(Class klass) {
final type = _annotationsDefineRoot(klass.annotations);
if (type != null) {
@@ -199,10 +213,18 @@
final Set<Member> _membersReferencedFromNativeCode = new Set<Member>();
final Set<Member> _dynamicallyOverriddenMembers = new Set<Member>();
final Set<Class> _classesReferencedFromNativeCode = new Set<Class>();
+ final Set<Library> _librariesReferencedFromNativeCode = new Set<Library>();
final PragmaAnnotationParser _matcher;
NativeCodeOracle(this._libraryIndex, this._matcher);
+ void addLibraryReferencedFromNativeCode(Library library) {
+ _librariesReferencedFromNativeCode.add(library);
+ }
+
+ bool isLibraryReferencedFromNativeCode(Library library) =>
+ _librariesReferencedFromNativeCode.contains(library);
+
void addClassReferencedFromNativeCode(Class klass) {
_classesReferencedFromNativeCode.add(klass);
}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 6e4f47f..6bc5097 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -852,6 +852,8 @@
}
bool isLibraryUsed(Library l) => _usedLibraries.contains(l);
+ bool isLibraryReferencedFromNativeCode(Library l) =>
+ typeFlowAnalysis.nativeCodeOracle.isLibraryReferencedFromNativeCode(l);
bool isClassReferencedFromNativeCode(Class c) =>
typeFlowAnalysis.nativeCodeOracle.isClassReferencedFromNativeCode(c);
bool isClassUsed(Class c) => _usedClasses.contains(c);
@@ -1910,7 +1912,9 @@
@override
TreeNode visitLibrary(Library node, TreeNode? removalSentinel) {
- if (!shaker.isLibraryUsed(node) && node.importUri.scheme != 'dart') {
+ if (!shaker.isLibraryUsed(node) &&
+ !shaker.isLibraryReferencedFromNativeCode(node) &&
+ node.importUri.scheme != 'dart') {
return removalSentinel!;
}
_additionalDeps.clear();
diff --git a/pkg/vm/test/native_assets/synthesizer_test.dart b/pkg/vm/test/native_assets/synthesizer_test.dart
index 59538a6..409cb6e 100644
--- a/pkg/vm/test/native_assets/synthesizer_test.dart
+++ b/pkg/vm/test/native_assets/synthesizer_test.dart
@@ -29,20 +29,24 @@
mode: NonNullableByDefaultCompiledMode.Strong,
);
final libraryToString = kernelLibraryToString(component.libraries.single);
- final expectedKernel = '''@#C9
+ final expectedKernel = '''@#C3
+@#C12
library;
import self as self;
constants {
- #C1 = "vm:ffi:native-assets"
- #C2 = "linux_x64"
- #C3 = "package:foo/foo.dart"
- #C4 = "absolute"
- #C5 = "/path/to/libfoo.so"
- #C6 = <dynamic>[#C4, #C5]
- #C7 = <dynamic, dynamic>{#C3:#C6}
- #C8 = <dynamic, dynamic>{#C2:#C7}
- #C9 = #lib1::pragma {name:#C1, options:#C8}
+ #C1 = "vm:entry-point"
+ #C2 = null
+ #C3 = #lib1::pragma {name:#C1, options:#C2}
+ #C4 = "vm:ffi:native-assets"
+ #C5 = "linux_x64"
+ #C6 = "package:foo/foo.dart"
+ #C7 = "absolute"
+ #C8 = "/path/to/libfoo.so"
+ #C9 = <dynamic>[#C7, #C8]
+ #C10 = <dynamic, dynamic>{#C6:#C9}
+ #C11 = <dynamic, dynamic>{#C5:#C10}
+ #C12 = #lib1::pragma {name:#C4, options:#C11}
}
''';
expect(libraryToString, equals(expectedKernel));
diff --git a/tests/ffi/native_assets/asset_absolute_test.dart b/tests/ffi/native_assets/asset_absolute_test.dart
index 3e312ae..eb11f3f 100644
--- a/tests/ffi/native_assets/asset_absolute_test.dart
+++ b/tests/ffi/native_assets/asset_absolute_test.dart
@@ -61,6 +61,7 @@
runtime: Runtime.aot,
arguments: [runTestsArg],
nativeAssetsYaml: nativeAssetsYaml,
+ protobufAwareTreeshaking: true,
);
}
diff --git a/tests/ffi/native_assets/asset_executable_test.dart b/tests/ffi/native_assets/asset_executable_test.dart
index b7f2669..baafe87 100644
--- a/tests/ffi/native_assets/asset_executable_test.dart
+++ b/tests/ffi/native_assets/asset_executable_test.dart
@@ -49,6 +49,7 @@
runtime: Runtime.jit,
arguments: [runTestsArg],
nativeAssetsYaml: nativeAssetsYaml,
+ protobufAwareTreeshaking: true,
);
await invokeSelf(
selfSourceUri: selfSourceUri,
diff --git a/tests/ffi/native_assets/asset_library_annotation_test.dart b/tests/ffi/native_assets/asset_library_annotation_test.dart
index b70eb16..d960239 100644
--- a/tests/ffi/native_assets/asset_library_annotation_test.dart
+++ b/tests/ffi/native_assets/asset_library_annotation_test.dart
@@ -53,6 +53,7 @@
runtime: Runtime.jit,
arguments: [runTestsArg],
nativeAssetsYaml: nativeAssetsYaml,
+ protobufAwareTreeshaking: true,
);
await invokeSelf(
selfSourceUri: selfSourceUri,
diff --git a/tests/ffi/native_assets/asset_process_test.dart b/tests/ffi/native_assets/asset_process_test.dart
index 63b0374..d30a98c 100644
--- a/tests/ffi/native_assets/asset_process_test.dart
+++ b/tests/ffi/native_assets/asset_process_test.dart
@@ -60,6 +60,7 @@
runtime: Runtime.appjit,
arguments: [runTestsArg],
nativeAssetsYaml: nativeAssetsYaml,
+ protobufAwareTreeshaking: true,
);
await invokeSelf(
selfSourceUri: selfSourceUri,
diff --git a/tests/ffi/native_assets/asset_relative_test.dart b/tests/ffi/native_assets/asset_relative_test.dart
index 05bd2ea..c0cfb7a 100644
--- a/tests/ffi/native_assets/asset_relative_test.dart
+++ b/tests/ffi/native_assets/asset_relative_test.dart
@@ -51,6 +51,7 @@
relativePath: RelativePath.same,
arguments: [runTestsArg],
useSymlink: true,
+ protobufAwareTreeshaking: true,
);
await invokeSelf(
selfSourceUri: selfSourceUri,
@@ -58,6 +59,7 @@
relativePath: RelativePath.down,
arguments: [runTestsArg],
useSymlink: true,
+ protobufAwareTreeshaking: false,
);
await invokeSelf(
selfSourceUri: selfSourceUri,
@@ -69,6 +71,7 @@
relativePath: RelativePath.up,
arguments: [runTestsArg],
useSymlink: true,
+ protobufAwareTreeshaking: true,
);
}
@@ -87,6 +90,7 @@
AotCompile aotCompile = AotCompile.elf,
RelativePath relativePath = RelativePath.same,
bool useSymlink = false,
+ required bool protobufAwareTreeshaking,
}) async {
await withTempDir((Uri tempUri) async {
final nestedUri = tempUri.resolve('nested/');
@@ -123,6 +127,7 @@
nativeAssetsYaml: nativeAssetsYaml,
runtime: runtime,
kernelCombine: kernelCombine,
+ protobufAwareTreeshaking: protobufAwareTreeshaking,
aotCompile: aotCompile,
runArguments: arguments,
useSymlink: useSymlink,
diff --git a/tests/ffi/native_assets/asset_system_test.dart b/tests/ffi/native_assets/asset_system_test.dart
index ede072a..7b1d5ca 100644
--- a/tests/ffi/native_assets/asset_system_test.dart
+++ b/tests/ffi/native_assets/asset_system_test.dart
@@ -68,6 +68,7 @@
runtime: Runtime.aot,
arguments: [runTestsArg],
nativeAssetsYaml: nativeAssetsYaml,
+ protobufAwareTreeshaking: true,
);
}
diff --git a/tests/ffi/native_assets/helpers.dart b/tests/ffi/native_assets/helpers.dart
index c13ebce..51aa6b3 100644
--- a/tests/ffi/native_assets/helpers.dart
+++ b/tests/ffi/native_assets/helpers.dart
@@ -47,6 +47,9 @@
final genKernelUri =
sdkUriAbsolute.resolve('pkg/vm/tool/gen_kernel$standaloneExtension');
+final protobufAwareTreeshakerUri =
+ sdkUriAbsolute.resolve('pkg/vm/bin/protobuf_aware_treeshaker.dart');
+
final genSnapshotUri =
buildUriAbsolute.resolve('gen_snapshot$standaloneExtensionExe');
@@ -80,6 +83,8 @@
if (!Platform.environment.containsKey(keepTempKey) ||
Platform.environment[keepTempKey]!.isEmpty) {
await tempDirResolved.delete(recursive: true);
+ } else {
+ print('Keeping $tempDirResolved');
}
}
}
@@ -161,12 +166,15 @@
required Uri nativeAssetsUri,
required Runtime runtime,
required KernelCombine kernelCombine,
+ required bool protobufAwareTreeshaking,
}) async {
+ final preTreeshakenDill = tempUri.resolve('pre_treeshaken.dill');
+
switch (kernelCombine) {
case KernelCombine.source:
await runGenKernel(
runtime: runtime,
- outputUri: outputUri,
+ outputUri: protobufAwareTreeshaking ? preTreeshakenDill : outputUri,
inputUri: dartProgramUri,
nativeAssetsUri: nativeAssetsUri,
);
@@ -189,7 +197,9 @@
await File.fromUri(programDillUri).readAsBytes();
final nativeAssetKernelBytes =
await File.fromUri(nativeAssetsDillUri).readAsBytes();
- await File.fromUri(outputUri).writeAsBytes(
+ await File.fromUri(
+ protobufAwareTreeshaking ? preTreeshakenDill : outputUri,
+ ).writeAsBytes(
[
...programKernelBytes,
...nativeAssetKernelBytes,
@@ -197,6 +207,17 @@
flush: true,
);
}
+
+ if (protobufAwareTreeshaking) {
+ await runDart(
+ scriptUri: protobufAwareTreeshakerUri,
+ arguments: [
+ if (runtime == Runtime.aot) '--aot',
+ /*<input.dill>*/ preTreeshakenDill.toFilePath(),
+ /*<output.dill>*/ outputUri.toFilePath(),
+ ],
+ );
+ }
}
Future<void> runGenSnapshot({
@@ -335,6 +356,7 @@
required String nativeAssetsYaml,
required Runtime runtime,
required KernelCombine kernelCombine,
+ required bool protobufAwareTreeshaking,
AotCompile aotCompile = AotCompile.elf,
required List<String> runArguments,
bool useSymlink = false,
@@ -350,6 +372,7 @@
nativeAssetsUri: nativeAssetsUri,
runtime: runtime,
kernelCombine: kernelCombine,
+ protobufAwareTreeshaking: protobufAwareTreeshaking,
);
switch (runtime) {
@@ -452,6 +475,7 @@
Runtime runtime = Runtime.jit,
KernelCombine kernelCombine = KernelCombine.source,
AotCompile aotCompile = AotCompile.elf,
+ bool protobufAwareTreeshaking = false,
}) async {
await withTempDir((Uri tempUri) async {
await compileAndRun(
@@ -460,6 +484,7 @@
nativeAssetsYaml: nativeAssetsYaml,
runtime: runtime,
kernelCombine: kernelCombine,
+ protobufAwareTreeshaking: protobufAwareTreeshaking,
aotCompile: aotCompile,
runArguments: arguments,
);