mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:49:17 +00:00
Add StackTrace.current getter.
R=floitsch@google.com, iposva@google.com, sra@google.com Review URL: https://codereview.chromium.org/1448003002.
This commit is contained in:
parent
594183e0db
commit
027b8dca39
|
@ -5,6 +5,7 @@
|
|||
* `Base64Decoder.convert` now takes optional `start` and `end` parameters.
|
||||
|
||||
* `dart:core`
|
||||
* Added `current` getter to `StackTrace` class.
|
||||
* Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
|
||||
return type.
|
||||
* Added `growable` parameter to `List.filled` constructor.
|
||||
|
|
|
@ -73,3 +73,7 @@ class _SyncIterator implements Iterator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
patch class StackTrace {
|
||||
/* patch */ static StackTrace get current native "StackTrace_current";
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
namespace dart {
|
||||
|
||||
static void IterateFrames(const GrowableObjectArray& code_list,
|
||||
const GrowableObjectArray& pc_offset_list) {
|
||||
const GrowableObjectArray& pc_offset_list,
|
||||
int skip_frames) {
|
||||
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
|
||||
StackFrame* frame = frames.NextFrame();
|
||||
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
|
||||
|
@ -19,15 +20,35 @@ static void IterateFrames(const GrowableObjectArray& code_list,
|
|||
Smi& offset = Smi::Handle();
|
||||
while (frame != NULL) {
|
||||
if (frame->IsDartFrame()) {
|
||||
code = frame->LookupDartCode();
|
||||
offset = Smi::New(frame->pc() - code.EntryPoint());
|
||||
code_list.Add(code);
|
||||
pc_offset_list.Add(offset);
|
||||
if (skip_frames > 0) {
|
||||
skip_frames--;
|
||||
} else {
|
||||
code = frame->LookupDartCode();
|
||||
offset = Smi::New(frame->pc() - code.EntryPoint());
|
||||
code_list.Add(code);
|
||||
pc_offset_list.Add(offset);
|
||||
}
|
||||
}
|
||||
frame = frames.NextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a Stacktrace object from the current stack.
|
||||
//
|
||||
// Skips the first skip_frames Dart frames.
|
||||
static const Stacktrace& GetCurrentStacktrace(int skip_frames) {
|
||||
const GrowableObjectArray& code_list =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
const GrowableObjectArray& pc_offset_list =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
IterateFrames(code_list, pc_offset_list, skip_frames);
|
||||
const Array& code_array = Array::Handle(Array::MakeArray(code_list));
|
||||
const Array& pc_offset_array =
|
||||
Array::Handle(Array::MakeArray(pc_offset_list));
|
||||
const Stacktrace& stacktrace = Stacktrace::Handle(
|
||||
Stacktrace::New(code_array, pc_offset_array));
|
||||
return stacktrace;
|
||||
}
|
||||
|
||||
// An utility method for convenient printing of dart stack traces when
|
||||
// inside 'gdb'. Note: This function will only work when there is a
|
||||
|
@ -35,17 +56,13 @@ static void IterateFrames(const GrowableObjectArray& code_list,
|
|||
// set in dart code and control is got inside 'gdb' without going through
|
||||
// the runtime or native transition stub.
|
||||
void _printCurrentStacktrace() {
|
||||
const GrowableObjectArray& code_list =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
const GrowableObjectArray& pc_offset_list =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
IterateFrames(code_list, pc_offset_list);
|
||||
const Array& code_array = Array::Handle(Array::MakeArray(code_list));
|
||||
const Array& pc_offset_array =
|
||||
Array::Handle(Array::MakeArray(pc_offset_list));
|
||||
const Stacktrace& stacktrace = Stacktrace::Handle(
|
||||
Stacktrace::New(code_array, pc_offset_array));
|
||||
const Stacktrace& stacktrace = GetCurrentStacktrace(0);
|
||||
OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
|
||||
const Stacktrace& stacktrace = GetCurrentStacktrace(1);
|
||||
return stacktrace.raw();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -151,6 +151,7 @@ namespace dart {
|
|||
V(DateNatives_localTimeZoneAdjustmentInSeconds, 0) \
|
||||
V(AssertionError_throwNew, 2) \
|
||||
V(Async_rethrow, 2) \
|
||||
V(StackTrace_current, 0) \
|
||||
V(TypeError_throwNew, 5) \
|
||||
V(FallThroughError_throwNew, 1) \
|
||||
V(AbstractClassInstantiationError_throwNew, 2) \
|
||||
|
|
|
@ -5,21 +5,22 @@
|
|||
// Patch file for dart:core classes.
|
||||
import "dart:_internal" as _symbol_dev;
|
||||
import 'dart:_interceptors';
|
||||
import 'dart:_js_helper' show patch,
|
||||
import 'dart:_js_helper' show checkInt,
|
||||
Closure,
|
||||
ConstantMap,
|
||||
getRuntimeType,
|
||||
JsLinkedHashMap;
|
||||
jsonEncodeNative,
|
||||
JSSyntaxRegExp,
|
||||
NoInline,
|
||||
objectHashCode,
|
||||
patch,
|
||||
patch_full,
|
||||
patch_lazy,
|
||||
patch_startup,
|
||||
checkInt,
|
||||
getRuntimeType,
|
||||
jsonEncodeNative,
|
||||
JSSyntaxRegExp,
|
||||
Primitives,
|
||||
ConstantMap,
|
||||
stringJoinUnchecked,
|
||||
objectHashCode,
|
||||
Closure,
|
||||
readHttp,
|
||||
JsLinkedHashMap;
|
||||
stringJoinUnchecked,
|
||||
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
|
||||
|
@ -671,3 +672,24 @@ class _Resource implements Resource {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
class StackTrace {
|
||||
@patch
|
||||
@NoInline()
|
||||
static StackTrace get current {
|
||||
var error = JS('', 'new Error()');
|
||||
var stack = JS('String|Null', '#.stack', error);
|
||||
if (stack is String) return new StackTrace.fromString(stack);
|
||||
if (JS('', 'Error.captureStackTrace') != null) {
|
||||
JS('void', 'Error.captureStackTrace(#)', error);
|
||||
var stack = JS('String|Null', '#.stack', error);
|
||||
if (stack is String) return new StackTrace.fromString(stack);
|
||||
}
|
||||
try {
|
||||
throw 0;
|
||||
} catch (_, stackTrace) {
|
||||
return stackTrace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,18 @@ abstract class StackTrace {
|
|||
*/
|
||||
factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
|
||||
|
||||
/**
|
||||
* Returns a representation of the current stack trace.
|
||||
*
|
||||
* This is similar to what can be achieved by doing:
|
||||
*
|
||||
* try { throw 0; } catch (_, stack) { return stack; }
|
||||
*
|
||||
* The getter achieves this without throwing, except on platforms that
|
||||
* have no other way to get a stack trace.
|
||||
*/
|
||||
external static StackTrace get current;
|
||||
|
||||
/**
|
||||
* Returns a [String] representation of the stack trace.
|
||||
*
|
||||
|
|
32
tests/corelib/stacktrace_current_test.dart
Normal file
32
tests/corelib/stacktrace_current_test.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2015, 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.
|
||||
|
||||
import "dart:convert" show LineSplitter;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
var st0;
|
||||
var st1;
|
||||
// Primitive way to get stack trace,.
|
||||
try { throw 0; } catch (_, s) { st0 = s; }
|
||||
st1 = StackTrace.current;
|
||||
|
||||
var st0s = findMain(st0);
|
||||
var st1s = findMain(st1);
|
||||
// Stack traces are not equal (contains at least a different line number,
|
||||
// and possible different frame numbers).
|
||||
// They are *similar*, so check that they agree on everything but numbers.
|
||||
var digits = new RegExp(r"\d+");
|
||||
Expect.equals(st0s.replaceAll(digits, "0"), st1s.replaceAll(digits, "0"));
|
||||
}
|
||||
|
||||
String findMain(StackTrace stack) {
|
||||
var string = "$stack";
|
||||
var lines = LineSplitter.split(string).toList();
|
||||
while (lines.isNotEmpty && !lines.first.contains("main")) {
|
||||
lines.removeAt(0);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
// Copyright (c) 2013, 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.
|
||||
|
|
Loading…
Reference in a new issue