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:
Lasse R.H. Nielsen 2015-11-24 08:26:03 +01:00
parent 594183e0db
commit 027b8dca39
8 changed files with 114 additions and 26 deletions

View file

@ -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.

View file

@ -73,3 +73,7 @@ class _SyncIterator implements Iterator {
}
}
}
patch class StackTrace {
/* patch */ static StackTrace get current native "StackTrace_current";
}

View file

@ -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

View file

@ -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) \

View file

@ -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;
}
}
}

View file

@ -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.
*

View 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");
}

View file

@ -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.