Be lazier when capturing stack traces.

It turns out that capturing stack traces is cheap; converting them to strings is
what's so expensive.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//14647003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/stack_trace@22205 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkgs/stack_trace/lib/src/lazy_trace.dart b/pkgs/stack_trace/lib/src/lazy_trace.dart
new file mode 100644
index 0000000..8c44829
--- /dev/null
+++ b/pkgs/stack_trace/lib/src/lazy_trace.dart
@@ -0,0 +1,34 @@
+// 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.
+
+library lazy_trace;
+
+import 'frame.dart';
+import 'trace.dart';
+
+/// A thunk for lazily constructing a [Trace].
+typedef Trace TraceThunk();
+
+/// A wrapper around a [TraceThunk]. This works around issue 9579 by avoiding
+/// the conversion of native [StackTrace]s to strings until it's absolutely
+/// necessary.
+class LazyTrace implements Trace {
+  final TraceThunk _thunk;
+  Trace _inner;
+
+  LazyTrace(this._thunk);
+
+  Trace get _trace {
+    if (_inner == null) _inner = _thunk();
+    return _inner;
+  }
+
+  List<Frame> get frames => _trace.frames;
+  String get stackTrace => _trace.stackTrace;
+  String get fullStackTrace => _trace.fullStackTrace;
+  Trace get terse => new LazyTrace(() => _trace.terse);
+  Trace foldFrames(bool predicate(frame)) =>
+    new LazyTrace(() => _trace.foldFrames(predicate));
+  String toString() => _trace.toString();
+}
diff --git a/pkgs/stack_trace/lib/src/trace.dart b/pkgs/stack_trace/lib/src/trace.dart
index 54f99db..ffea498 100644
--- a/pkgs/stack_trace/lib/src/trace.dart
+++ b/pkgs/stack_trace/lib/src/trace.dart
@@ -9,6 +9,7 @@
 import 'dart:math' as math;
 
 import 'frame.dart';
+import 'lazy_trace.dart';
 
 final _patchRegExp = new RegExp(r"-patch$");
 
@@ -42,7 +43,7 @@
       throw '';
     } catch (_, nativeTrace) {
       var trace = new Trace.from(nativeTrace);
-      return new Trace(trace.frames.skip(level + 1));
+      return new LazyTrace(() => new Trace(trace.frames.skip(level + 1)));
     }
   }
 
@@ -52,7 +53,7 @@
   /// a [Trace], it will be returned as-is.
   factory Trace.from(StackTrace trace) {
     if (trace is Trace) return trace;
-    return new Trace.parse(trace.toString());
+    return new LazyTrace(() => new Trace.parse(trace.toString()));
   }
 
   /// Parses a string representation of a stack trace.