dc62c9c3c2
Instead of being part of the --trace-precompiler output, there is
is a new flag --write-retained-reasons-to=<path>.
To allow for non-functions to have reasons for retention, the
JSON objects in the array now have one additional field:
* type: a string, the C++ type of the Dart object.
This CL also wraps all the machinery in a RetainedReasonsWriter
class instead of putting it in the Precompiler interface.
TEST=vm/dart{,2}/use_trace_precompiler_flag
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try
Change-Id: Ifa40ac64fdcbdad5114499425c7f8b08e327fa76
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190525
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
111 lines
3.9 KiB
Dart
111 lines
3.9 KiB
Dart
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// This test ensures that --trace-precompiler runs without issue and prints
|
|
// valid JSON for reasons to retain objects.
|
|
|
|
// OtherResources=use_dwarf_stack_traces_flag_program.dart
|
|
|
|
import "dart:convert";
|
|
import "dart:io";
|
|
|
|
import 'package:expect/expect.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import 'use_flag_test_helper.dart';
|
|
|
|
main(List<String> args) async {
|
|
if (!isAOTRuntime) {
|
|
return; // Running in JIT: AOT binaries not available.
|
|
}
|
|
|
|
if (Platform.isAndroid) {
|
|
return; // SDK tree and dart_bootstrap not available on the test device.
|
|
}
|
|
|
|
// These are the tools we need to be available to run on a given platform:
|
|
if (!await testExecutable(genSnapshot)) {
|
|
throw "Cannot run test as $genSnapshot not available";
|
|
}
|
|
if (!await testExecutable(aotRuntime)) {
|
|
throw "Cannot run test as $aotRuntime not available";
|
|
}
|
|
if (!File(platformDill).existsSync()) {
|
|
throw "Cannot run test as $platformDill does not exist";
|
|
}
|
|
|
|
await withTempDir('trace-precompiler-flag-test', (String tempDir) async {
|
|
final cwDir = path.dirname(Platform.script.toFilePath());
|
|
// We can just reuse the program for the use_dwarf_stack_traces test.
|
|
final script = path.join(cwDir, 'use_dwarf_stack_traces_flag_program.dart');
|
|
final scriptDill = path.join(tempDir, 'flag_program.dill');
|
|
|
|
// Compile script to Kernel IR.
|
|
await run(genKernel, <String>[
|
|
'--aot',
|
|
'--platform=$platformDill',
|
|
'-o',
|
|
scriptDill,
|
|
script,
|
|
]);
|
|
|
|
// Run the AOT compiler with every enabled/disabled combination of the
|
|
// following flags that affect object retention:
|
|
final retentionFlags = [
|
|
'retain-function-objects',
|
|
'dwarf-stack-traces-mode'
|
|
];
|
|
|
|
for (var i = 0; i < 1 << retentionFlags.length; i++) {
|
|
final flags = <String>[];
|
|
for (var j = 0; j < retentionFlags.length; j++) {
|
|
final buffer = StringBuffer('--');
|
|
if ((i & (1 << j)) == 0) {
|
|
buffer.write('no-');
|
|
}
|
|
buffer.write(retentionFlags[j]);
|
|
flags.add(buffer.toString());
|
|
}
|
|
await testTracePrecompiler(tempDir, scriptDill, flags);
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<void> testTracePrecompiler(
|
|
String tempDir, String scriptDill, List<String> flags) async {
|
|
final reasonsFile = path.join(tempDir, 'reasons.json');
|
|
final snapshot = path.join(tempDir, 'snapshot.so');
|
|
final result = await run(genSnapshot, <String>[
|
|
...flags,
|
|
'--write-retained-reasons-to=$reasonsFile',
|
|
'--snapshot-kind=app-aot-elf',
|
|
'--elf=$snapshot',
|
|
scriptDill,
|
|
]);
|
|
|
|
final stream = Stream.fromFuture(File(reasonsFile).readAsString());
|
|
final decisionsJson = await json.decoder.bind(stream).first;
|
|
Expect.isTrue(decisionsJson is List, 'not a list of decisions');
|
|
Expect.isTrue((decisionsJson as List).every((o) => o is Map),
|
|
'not a list of decision objects');
|
|
final decisions = (decisionsJson as List).map((o) => o as Map);
|
|
for (final m in decisions) {
|
|
Expect.isTrue(m.containsKey("name"), 'no name field in decision');
|
|
Expect.isTrue(m["name"] is String, 'name field is not a string');
|
|
Expect.isTrue(m.containsKey("type"), 'no type field in decision');
|
|
Expect.isTrue(m["type"] is String, 'type field is not a string');
|
|
Expect.isTrue(m.containsKey("retained"), 'no retained field in decision');
|
|
Expect.isTrue(m["retained"] is bool, 'retained field is not a boolean');
|
|
if (m["retained"] as bool) {
|
|
Expect.isTrue(m.containsKey("reasons"), 'no reasons field in decision');
|
|
Expect.isTrue(m["reasons"] is List, 'reasons field is not a list');
|
|
final reasons = m["reasons"] as List;
|
|
Expect.isFalse(reasons.isEmpty, 'reasons list should not be empty');
|
|
for (final o in reasons) {
|
|
Expect.isTrue(o is String, 'reason is not a string');
|
|
}
|
|
}
|
|
}
|
|
}
|