Custom format errors and exceptions to show traces

Fixes #34529

Change-Id: If5142a9c11808af50d1b7a04346e53e980cce3e6
Reviewed-on: https://dart-review.googlesource.com/76101
Reviewed-by: Jenny Messerly <jmesserly@google.com>
Commit-Queue: Vijay Menon <vsm@google.com>
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index 358b884..3ee1721 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -37,6 +37,8 @@
 final Function(Object) getOwnPropertySymbols =
     JS('', 'Object.getOwnPropertySymbols');
 
+final Function(Object) getPrototypeOf = JS('', 'Object.getPrototypeOf');
+
 /// This error indicates a strong mode specific failure, other than a type
 /// assertion failure (TypeError) or CastError.
 void throwTypeError(String message) {
diff --git a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
index 492291a..86592dc 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
@@ -106,7 +106,7 @@
 
     if (!walkPrototypeChain) break;
 
-    sig = safeGetProperty(sig, '__proto__');
+    sig = dart.getPrototypeOf(sig);
   }
 }
 
@@ -462,6 +462,7 @@
       IterableSpanFormatter(),
       MapEntryFormatter(),
       StackTraceFormatter(),
+      ErrorAndExceptionFormatter(),
       FunctionFormatter(),
       HeritageClauseFormatter(),
       LibraryModuleFormatter(),
@@ -802,7 +803,7 @@
   accept(object, config) => object is IterableSpan;
 
   String preview(object) {
-    return '[${object.start}...${object.end-1}]';
+    return '[${object.start}...${object.end - 1}]';
   }
 
   bool hasChildren(object) => true;
@@ -810,6 +811,45 @@
   List<NameValuePair> children(object) => object.children();
 }
 
+/// Formatter for Dart Errors and Exceptions.
+class ErrorAndExceptionFormatter extends ObjectFormatter {
+  static final RegExp _pattern = RegExp(r'\d+\:\d+');
+
+  accept(object, config) => object is Error || object is Exception;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    var trace = dart.stackTrace(object);
+    // TODO(vsm): Pull our stack mapping logic here.  We should aim to
+    // provide the first meaningful stack frame.
+    var line = '$trace'.split('\n').firstWhere(
+        (l) =>
+            l.contains(_pattern) &&
+            !l.contains('dart:sdk') &&
+            !l.contains('dart_sdk'),
+        orElse: () => null);
+    return line != null ? '${object} at ${line}' : '${object}';
+  }
+
+  List<NameValuePair> children(object) {
+    var trace = dart.stackTrace(object);
+    var entries = LinkedHashSet<NameValuePair>();
+    entries.add(NameValuePair(name: 'stackTrace', value: trace));
+    addInstanceMembers(object, entries);
+    addMetadataChildren(object, entries);
+    return entries.toList();
+  }
+
+  // Add an ObjectFormatter view underneath.
+  void addInstanceMembers(object, Set<NameValuePair> ret) {
+    ret.add(NameValuePair(
+        name: "[[instance members]]",
+        value: object,
+        config: JsonMLConfig.asObject));
+  }
+}
+
 class StackTraceFormatter implements Formatter {
   accept(object, config) => object is StackTrace;