blob: a9fe0f3bb8c9dc90456763565061c95df89db23a [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.
/// VMOptions=--dwarf-stack-traces --save-debugging-info=dwarf_invisible_functions.so
import 'dart:io';
import 'package:native_stack_traces/native_stack_traces.dart';
import 'package:path/path.dart' as path;
import 'dwarf_stack_trace_test.dart' as dwarf_stack_trace_test;
const int LINE_A = 23;
const int LINE_B = 29;
const int LINE_C = 36;
const int LINE_D = 44;
const int LINE_E = 56;
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
throw // force linebreak with dart format // LINE_A
"Hello, Dwarf!";
}
@pragma("vm:never-inline")
foo() {
bar(); // LINE_B
}
@pragma("vm:never-inline")
bazz(void Function() func) {
// Call through tear-off (implicit closure function) which should be
// omitted from the stack trace.
func(); // LINE_C
}
class A<T> {
A();
@pragma("vm:never-inline")
void add(T x) {
bazz(foo); // LINE_D
}
}
dynamic aa = int.parse('1') == 1 ? A() : [];
Future<void> main() async {
String rawStack = "";
try {
// Dynamic call to a generic-covariant method goes through the
// dynamic invocation forwarder function, which should be
// omitted from the stack trace.
aa.add(42); // LINE_E
} catch (e, st) {
rawStack = st.toString();
}
if (path.basenameWithoutExtension(Platform.executable) !=
"dart_precompiled_runtime") {
return; // Not running from an AOT compiled snapshot.
}
if (Platform.isAndroid) {
return; // Generated dwarf.so not available on the test device.
}
final dwarf = Dwarf.fromFile("dwarf_invisible_functions.so")!;
await dwarf_stack_trace_test.checkStackTrace(
rawStack, dwarf, expectedCallsInfo);
}
final expectedCallsInfo = <List<DartCallInfo>>[
// Frame 1: the throw in bar, which was inlined
// into foo (so we'll get information for two calls for that PC address).
[
DartCallInfo(
function: "bar",
filename: "dwarf_stack_trace_invisible_functions_test.dart",
line: LINE_A,
column: 3,
inlined: true),
DartCallInfo(
function: "foo",
filename: "dwarf_stack_trace_invisible_functions_test.dart",
line: LINE_B,
column: 3,
inlined: false)
],
// Frame 2: call to foo in bazz.
[
DartCallInfo(
function: "bazz",
filename: "dwarf_stack_trace_invisible_functions_test.dart",
line: LINE_C,
column: 3,
inlined: false)
],
// Frame 3: call to bazz in A.method.
[
DartCallInfo(
function: "A.add",
filename: "dwarf_stack_trace_invisible_functions_test.dart",
line: LINE_D,
column: 5,
inlined: false)
],
// Frame 4: the call to foo in main.
[
DartCallInfo(
function: "main",
filename: "dwarf_stack_trace_invisible_functions_test.dart",
line: LINE_E,
column: 8,
inlined: false)
],
// Don't assume anything about any of the frames below the main,
// as this makes the test too brittle.
];