blob: 7ea2d60de37ec9d7aa380238da0374c2a743f24a [file] [log] [blame]
// 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');
}
}
}
}