Skip to content

Commit 027b8dc

Browse files
committed
Add StackTrace.current getter.
R=floitsch@google.com, iposva@google.com, sra@google.com Review URL: https://codereview.chromium.org/1448003002.
1 parent 594183e commit 027b8dc

File tree

8 files changed

+112
-24
lines changed

8 files changed

+112
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* `Base64Decoder.convert` now takes optional `start` and `end` parameters.
66

77
* `dart:core`
8+
* Added `current` getter to `StackTrace` class.
89
* Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
910
return type.
1011
* Added `growable` parameter to `List.filled` constructor.

runtime/lib/core_patch.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,7 @@ class _SyncIterator implements Iterator {
7373
}
7474
}
7575
}
76+
77+
patch class StackTrace {
78+
/* patch */ static StackTrace get current native "StackTrace_current";
79+
}

runtime/lib/stacktrace.cc

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,41 +11,58 @@
1111
namespace dart {
1212

1313
static void IterateFrames(const GrowableObjectArray& code_list,
14-
const GrowableObjectArray& pc_offset_list) {
14+
const GrowableObjectArray& pc_offset_list,
15+
int skip_frames) {
1516
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
1617
StackFrame* frame = frames.NextFrame();
1718
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
1819
Code& code = Code::Handle();
1920
Smi& offset = Smi::Handle();
2021
while (frame != NULL) {
2122
if (frame->IsDartFrame()) {
22-
code = frame->LookupDartCode();
23-
offset = Smi::New(frame->pc() - code.EntryPoint());
24-
code_list.Add(code);
25-
pc_offset_list.Add(offset);
23+
if (skip_frames > 0) {
24+
skip_frames--;
25+
} else {
26+
code = frame->LookupDartCode();
27+
offset = Smi::New(frame->pc() - code.EntryPoint());
28+
code_list.Add(code);
29+
pc_offset_list.Add(offset);
30+
}
2631
}
2732
frame = frames.NextFrame();
2833
}
2934
}
3035

31-
32-
// An utility method for convenient printing of dart stack traces when
33-
// inside 'gdb'. Note: This function will only work when there is a
34-
// valid exit frame information. It will not work when a breakpoint is
35-
// set in dart code and control is got inside 'gdb' without going through
36-
// the runtime or native transition stub.
37-
void _printCurrentStacktrace() {
36+
// Creates a Stacktrace object from the current stack.
37+
//
38+
// Skips the first skip_frames Dart frames.
39+
static const Stacktrace& GetCurrentStacktrace(int skip_frames) {
3840
const GrowableObjectArray& code_list =
3941
GrowableObjectArray::Handle(GrowableObjectArray::New());
4042
const GrowableObjectArray& pc_offset_list =
4143
GrowableObjectArray::Handle(GrowableObjectArray::New());
42-
IterateFrames(code_list, pc_offset_list);
44+
IterateFrames(code_list, pc_offset_list, skip_frames);
4345
const Array& code_array = Array::Handle(Array::MakeArray(code_list));
4446
const Array& pc_offset_array =
4547
Array::Handle(Array::MakeArray(pc_offset_list));
4648
const Stacktrace& stacktrace = Stacktrace::Handle(
4749
Stacktrace::New(code_array, pc_offset_array));
50+
return stacktrace;
51+
}
52+
53+
// An utility method for convenient printing of dart stack traces when
54+
// inside 'gdb'. Note: This function will only work when there is a
55+
// valid exit frame information. It will not work when a breakpoint is
56+
// set in dart code and control is got inside 'gdb' without going through
57+
// the runtime or native transition stub.
58+
void _printCurrentStacktrace() {
59+
const Stacktrace& stacktrace = GetCurrentStacktrace(0);
4860
OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
4961
}
5062

63+
DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
64+
const Stacktrace& stacktrace = GetCurrentStacktrace(1);
65+
return stacktrace.raw();
66+
}
67+
5168
} // namespace dart

runtime/vm/bootstrap_natives.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ namespace dart {
151151
V(DateNatives_localTimeZoneAdjustmentInSeconds, 0) \
152152
V(AssertionError_throwNew, 2) \
153153
V(Async_rethrow, 2) \
154+
V(StackTrace_current, 0) \
154155
V(TypeError_throwNew, 5) \
155156
V(FallThroughError_throwNew, 1) \
156157
V(AbstractClassInstantiationError_throwNew, 2) \

sdk/lib/_internal/js_runtime/lib/core_patch.dart

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@
55
// Patch file for dart:core classes.
66
import "dart:_internal" as _symbol_dev;
77
import 'dart:_interceptors';
8-
import 'dart:_js_helper' show patch,
9-
patch_full,
10-
patch_lazy,
11-
patch_startup,
12-
checkInt,
8+
import 'dart:_js_helper' show checkInt,
9+
Closure,
10+
ConstantMap,
1311
getRuntimeType,
12+
JsLinkedHashMap;
1413
jsonEncodeNative,
1514
JSSyntaxRegExp,
16-
Primitives,
17-
ConstantMap,
18-
stringJoinUnchecked,
15+
NoInline,
1916
objectHashCode,
20-
Closure,
17+
patch,
18+
patch_full,
19+
patch_lazy,
20+
patch_startup,
21+
Primitives,
2122
readHttp,
22-
JsLinkedHashMap;
23+
stringJoinUnchecked,
2324

2425
import 'dart:_foreign_helper' show JS;
2526

@@ -671,3 +672,24 @@ class _Resource implements Resource {
671672
});
672673
}
673674
}
675+
676+
@patch
677+
class StackTrace {
678+
@patch
679+
@NoInline()
680+
static StackTrace get current {
681+
var error = JS('', 'new Error()');
682+
var stack = JS('String|Null', '#.stack', error);
683+
if (stack is String) return new StackTrace.fromString(stack);
684+
if (JS('', 'Error.captureStackTrace') != null) {
685+
JS('void', 'Error.captureStackTrace(#)', error);
686+
var stack = JS('String|Null', '#.stack', error);
687+
if (stack is String) return new StackTrace.fromString(stack);
688+
}
689+
try {
690+
throw 0;
691+
} catch (_, stackTrace) {
692+
return stackTrace;
693+
}
694+
}
695+
}

sdk/lib/core/stacktrace.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ abstract class StackTrace {
3030
*/
3131
factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
3232

33+
/**
34+
* Returns a representation of the current stack trace.
35+
*
36+
* This is similar to what can be achieved by doing:
37+
*
38+
* try { throw 0; } catch (_, stack) { return stack; }
39+
*
40+
* The getter achieves this without throwing, except on platforms that
41+
* have no other way to get a stack trace.
42+
*/
43+
external static StackTrace get current;
44+
3345
/**
3446
* Returns a [String] representation of the stack trace.
3547
*
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "dart:convert" show LineSplitter;
6+
7+
import "package:expect/expect.dart";
8+
9+
void main() {
10+
var st0;
11+
var st1;
12+
// Primitive way to get stack trace,.
13+
try { throw 0; } catch (_, s) { st0 = s; }
14+
st1 = StackTrace.current;
15+
16+
var st0s = findMain(st0);
17+
var st1s = findMain(st1);
18+
// Stack traces are not equal (contains at least a different line number,
19+
// and possible different frame numbers).
20+
// They are *similar*, so check that they agree on everything but numbers.
21+
var digits = new RegExp(r"\d+");
22+
Expect.equals(st0s.replaceAll(digits, "0"), st1s.replaceAll(digits, "0"));
23+
}
24+
25+
String findMain(StackTrace stack) {
26+
var string = "$stack";
27+
var lines = LineSplitter.split(string).toList();
28+
while (lines.isNotEmpty && !lines.first.contains("main")) {
29+
lines.removeAt(0);
30+
}
31+
return lines.join("\n");
32+
}

tests/language/stacktrace_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
32
// for details. All rights reserved. Use of this source code is governed by a
43
// BSD-style license that can be found in the LICENSE file.

0 commit comments

Comments
 (0)