Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(519)

Unified Diff: dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart

Issue 11858017: Nice messages on uncaught exceptions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address review comments and fix a type error Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
diff --git a/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index cc6d052cce473a4d293d4ddbcea5d028b473526d..60853523726971f18b71eeba915b000c5a3c581b 100644
--- a/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -951,30 +951,81 @@ class MathNatives {
}
/**
- * Throws the given Dart object as an exception by wrapping it in a
- * proper JavaScript error object and then throwing that. That gives
- * us a reasonable stack trace on most JavaScript implementations. The
- * code in [unwrapException] deals with getting the original Dart
+ * Wrap the given Dart object and record a stack trace.
+ *
+ * The code in [unwrapException] deals with getting the original Dart
* object out of the wrapper again.
*/
$throw(ex) {
if (ex == null) ex = const NullThrownError();
- var jsError = JS('var', r'new Error()');
- JS('void', r'#.name = #', jsError, ex);
- JS('void', r'#.description = #', jsError, ex);
- JS('void', r'#.dartException = #', jsError, ex);
- JS('void', r'#.toString = #', jsError,
- DART_CLOSURE_TO_JS(toStringWrapper));
- JS('void', r'throw #', jsError);
+ var wrapper = new DartError(ex);
+
+ if (JS('bool', 'Error.captureStackTrace')) {
+ // Use V8 API for recording a "fast" stack trace (this installs a
+ // "stack" property getter on [wrapper]).
+ JS('void', r'Error.captureStackTrace(#, #)',
+ wrapper, RAW_DART_FUNCTION_REF($throw));
+ } else {
+ // Otherwise, produce a stack trace and record it in the wrapper.
+ // This is a slower way to create a stack trace which works on
+ // some browsers, but may simply evaluate to null.
+ String stackTrace = JS('', 'new Error().stack');
+ JS('void', '#.stack = #', wrapper, stackTrace);
+ }
+ return wrapper;
}
/**
- * This method is installed as JavaScript toString method on exception
- * objects in [$throw]. So JavaScript 'this' binds to an instance of
- * JavaScript Error to which we have added a property 'dartException'
- * which holds a Dart object.
+ * Wrapper class for throwing exceptions.
*/
-toStringWrapper() => JS('', r'this.dartException').toString();
+class DartError {
+ /// The Dart object (or primitive JavaScript value) which was thrown.
+ final dartException;
+
+ DartError(this.dartException) {
+ // Install a toString method that the JavaScript system will call
+ // to format uncaught exceptions.
+ JS('void', '#.toString = #', this, DART_CLOSURE_TO_JS(toStringWrapper));
+ }
+
+ /**
+ * V8/Chrome installs a property getter, "stack", when calling
+ * Error.captureStackTrace (see [$throw]). In [$throw], we make sure
+ * that this property is always set.
+ */
+ String get stack => JS('', '#.stack', this);
+
+ /**
+ * This method can be invoked by calling toString from
+ * JavaScript. See the constructor of this class.
+ *
+ * We only expect this method to be called (indirectly) by the
+ * browser when an uncaught exception occurs. Instance of this class
+ * should never escape into Dart code (except for [$throw] above).
+ */
+ String toString() {
+ // If Error.captureStackTrace is available, accessing stack from
+ // this method would cause recursion because the stack property
+ // (on this object) is actually a getter which calls toString on
+ // this object (via the wrapper installed in this class'
+ // constructor). Fortunately, both Chrome and d8 prints the stack
+ // trace and Chrome even applies source maps to the stack
+ // trace. Remeber, this method is only ever invoked by the browser
+ // when an uncaught exception occurs.
+ if (JS('bool', 'Error.captureStackTrace') || (stack == null)) {
+ return dartException.toString();
+ } else {
+ return '$dartException\n$stack';
+ }
+ }
+
+ /**
+ * This method is installed as JavaScript toString method on
+ * [DartError]. So JavaScript 'this' binds to an instance of
+ * DartError.
+ */
+ static toStringWrapper() => JS('', r'this').toString();
+}
makeLiteralListConst(list) {
JS('bool', r'#.immutable$list = #', list, true);

Powered by Google App Engine
This is Rietveld 408576698