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

Unified Diff: tool/input_sdk/private/debugger.dart

Issue 1997473007: Fix debugger (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « tool/input_sdk/private/ddc_runtime/rtti.dart ('k') | tool/sdk_expected_errors.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tool/input_sdk/private/debugger.dart
diff --git a/tool/input_sdk/private/debugger.dart b/tool/input_sdk/private/debugger.dart
index e979ae5d063b56a4ed9c3366d3ce9738d90c760a..bab940b087d17d52b6a674ebf60b09be6a5ed37b 100644
--- a/tool/input_sdk/private/debugger.dart
+++ b/tool/input_sdk/private/debugger.dart
@@ -7,6 +7,8 @@ library dart._debugger;
import 'dart:_foreign_helper' show JS;
import 'dart:_runtime' as dart;
import 'dart:core';
+import 'dart:collection';
+import 'dart:html' as html;
vsm 2016/05/20 01:30:39 Nothing in dart:core, etc depends on debugger, rig
Jacob 2016/05/20 17:02:36 Nothing depends on the _debugger library. The only
/// Config object to pass to devtools to signal that an object should not be
/// formatted by the Dart formatter. This is used to specify that an Object
@@ -19,7 +21,6 @@ final int maxIterableChildrenToDisplay = 50;
var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter());
String _typeof(object) => JS('String', 'typeof #', object);
-bool _instanceof(object, clazz) => JS('bool', '# instanceof #', object, clazz);
List<String> getOwnPropertyNames(object) => JS('List<String>',
'dart.list(Object.getOwnPropertyNames(#), #)', object, String);
@@ -36,11 +37,6 @@ class JSNative {
JS('', '#[#]=#', object, name, value);
}
-bool isRegularDartObject(object) {
- if (_typeof(object) == 'function') return false;
- return _instanceof(object, JS('Type', '#', Object));
-}
-
String getObjectTypeName(object) {
var reifiedType = dart.getReifiedType(object);
if (reifiedType == null) {
@@ -58,8 +54,8 @@ String getTypeName(Type type) {
// TODO(jacobr): it would be nice if there was a way we could distinguish
// between a List<dynamic> created from Dart and an Array passed in from
// JavaScript.
- if (name == 'JSArray<dynamic>' ||
- name == 'JSObject<Array>') return 'List<dynamic>';
+ if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>')
+ return 'List<dynamic>';
return name;
}
@@ -69,7 +65,7 @@ String safePreview(object) {
if (preview != null) return preview;
return object.toString();
} catch (e) {
- return '<Exception thrown>';
+ return '<Exception thrown> $e';
}
}
@@ -92,6 +88,11 @@ class NameValuePair {
NameValuePair({this.name, this.value, bool skipDart})
: skipDart = skipDart == true;
+ // Define equality and hashCode so that NameValuePair can be used
+ // in a Set to dedupe entries with duplicate names.
+ operator ==(other) => other is NameValuePair && other.name == name;
+ int get hashCode => name.hashCode;
+
final String name;
final Object value;
final bool skipDart;
@@ -164,6 +165,18 @@ class JsonMLElement {
toJsonML() => _jsonML;
}
+/// Whether an object is a native JavaScript type where we should display the
+/// JavaScript view of the object instead of the custom Dart specific render
+/// of properties.
+bool isNativeJavaScriptObject(object) {
+ var type = _typeof(object);
+ // Treat Node objects as a native JavaScript type as the regular DOM render
+ // in devtools is superior to the dart specific view.
+ return (type != 'object' && type != 'function') ||
+ object is dart.JSObject ||
+ object is html.Node;
+}
+
/// Class implementing the Devtools Formatter API described by:
/// https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U
/// Specifically, a formatter implements a header, hasBody, and body method.
@@ -180,7 +193,9 @@ class JsonMLFormatter {
JsonMLFormatter(this._simpleFormatter);
header(object, config) {
- if (identical(config, skipDartConfig)) return null;
+ if (identical(config, skipDartConfig) || isNativeJavaScriptObject(object)) {
+ return null;
+ }
var c = _simpleFormatter.preview(object);
if (c == null) return null;
@@ -257,12 +272,21 @@ class DartFormatter {
}
String preview(object) {
- if (object == null) return 'null';
- if (object is num) return object.toString();
- if (object is String) return '"$object"';
+ try {
+ if (object == null ||
vsm 2016/05/20 01:30:39 null.toString()? perhaps return "null"?
Jacob 2016/05/20 17:02:36 null.toString is defined as "null" in Dart so we d
+ object is num ||
+ object is String ||
+ isNativeJavaScriptObject(object)) {
+ return object.toString();
+ }
- for (var formatter in _formatters) {
- if (formatter.accept(object)) return formatter.preview(object);
+ for (var formatter in _formatters) {
+ if (formatter.accept(object)) return formatter.preview(object);
+ }
+ } catch (e, trace) {
+ // Log formatter internal errors as unfortunately the devtools cannot
+ // be used to debug formatter errors.
+ html.window.console.error("Caught exception $e\n trace:\n$trace");
}
return null;
@@ -270,19 +294,28 @@ class DartFormatter {
bool hasChildren(object) {
if (object == null) return false;
-
- for (var formatter in _formatters) {
- if (formatter.accept(object)) return formatter.hasChildren(object);
+ try {
+ for (var formatter in _formatters) {
+ if (formatter.accept(object)) return formatter.hasChildren(object);
+ }
+ } catch (e, trace) {
+ // See comment for preview.
+ html.window.console
+ .error("[hasChildren] Caught exception $e\n trace:\n$trace");
}
-
return false;
}
List<NameValuePair> children(object) {
- if (object != null) {
- for (var formatter in _formatters) {
- if (formatter.accept(object)) return formatter.children(object);
+ try {
+ if (object != null) {
+ for (var formatter in _formatters) {
+ if (formatter.accept(object)) return formatter.children(object);
+ }
}
+ } catch (e, trace) {
+ // See comment for preview.
+ html.window.console.error("Caught exception $e\n trace:\n$trace");
}
return <NameValuePair>[];
}
@@ -290,61 +323,79 @@ class DartFormatter {
/// Default formatter for Dart Objects.
class ObjectFormatter extends Formatter {
- bool accept(object) => isRegularDartObject(object);
+ bool accept(object) => !isNativeJavaScriptObject(object);
String preview(object) => getObjectTypeName(object);
bool hasChildren(object) => true;
- /// Helper to add members walking up the prototype chain being careful
- /// to avoid properties that are Dart methods.
- _addMembers(current, object, List<NameValuePair> properties) {
- // TODO(jacobr): optionally distinguish properties and fields so that
- // it is safe to expand untrusted objects without side effects.
- var className = dart.getReifiedType(current).name;
- for (var name in getOwnPropertyNames(current)) {
- if (name == 'constructor' ||
- name == '__proto__' ||
- name == className) continue;
- if (hasMethod(object, name)) {
- continue;
- }
- var value;
- try {
- value = JSNative.getProperty(object, name);
- } catch (e) {
- value = '<Exception thrown>';
- }
- properties.add(new NameValuePair(name: name, value: value));
+ List<NameValuePair> children(object) {
+ var properties = new LinkedHashSet<NameValuePair>();
+ // Set of property names used to avoid duplicates.
+ addMetadataChildren(object, properties);
+
+ /// Helper to add members walking up the prototype chain being careful
+ /// to avoid properties that are Dart methods.
+ var protoChain = <Object>[];
+ var current = object;
+ while (current != null &&
+ !isNativeJavaScriptObject(current) &&
+ JS("bool", "# !== Object.prototype", current)) {
+ protoChain.add(current);
+ current = JSNative.getProperty(current, '__proto__');
}
- for (var symbol in getOwnPropertySymbols(current)) {
- var dartName = symbolName(symbol);
- if (hasMethod(object, dartName)) {
- continue;
- }
- var value;
- try {
- value = JSNative.getProperty(object, symbol);
- } catch (e) {
- value = '<Exception thrown>';
+
+ // We walk the prototype chain for symbol properties
+ // because they take priority and are accessed instead of
+ // Dart properties according to Dart calling conventions.
vsm 2016/05/20 01:30:39 We have some of this metadata encoded on the type
Jacob 2016/05/20 17:02:36 Agreed that would be much better. Adding a TODO. P
+ for (current in protoChain) {
+ for (var symbol in getOwnPropertySymbols(current)) {
+ var dartName = symbolName(symbol);
+ if (hasMethod(object, dartName)) {
+ continue;
+ }
+ // TODO(jacobr): find a cleaner solution than checking for dartx
+ String dartXPrefix = 'dartx.';
+ if (dartName.startsWith(dartXPrefix)) {
+ dartName = dartName.substring(dartXPrefix.length);
+ } else if (!dartName.startsWith('_')) {
+ // Dart method extension names should either be from dartx or should
+ // start with an _
+ continue;
+ }
+ var value;
+ try {
+ value = JSNative.getProperty(object, symbol);
+ } catch (e) {
+ value = '<Exception thrown> $e';
+ }
+ properties.add(new NameValuePair(name: dartName, value: value));
}
- properties.add(new NameValuePair(name: dartName, value: value));
}
- var base = JSNative.getProperty(current, '__proto__');
- if (base == null) return;
- if (isRegularDartObject(base)) {
- _addMembers(base, object, properties);
+
+ for (current in protoChain) {
+ // TODO(jacobr): optionally distinguish properties and fields so that
+ // it is safe to expand untrusted objects without side effects.
+ var className = dart.getReifiedType(current).name;
+ for (var name in getOwnPropertyNames(current)) {
+ if (customNames.contains(name) || name == className) continue;
vsm 2016/05/20 01:30:39 You're getting an SDK error on this. :-)
Jacob 2016/05/20 17:02:36 Wow. Fixed.
+ if (hasMethod(object, name)) {
+ continue;
+ }
+ var value;
+ try {
+ value = JSNative.getProperty(object, name);
+ } catch (e) {
+ value = '<Exception thrown> $e';
+ }
+ properties.add(new NameValuePair(name: name, value: value));
+ }
}
- }
- List<NameValuePair> children(object) {
- var properties = <NameValuePair>[];
- addMetadataChildren(object, properties);
- _addMembers(object, object, properties);
- return properties;
+ return properties.toList();
}
- addMetadataChildren(object, List<NameValuePair> ret) {
+ addMetadataChildren(object, Set<NameValuePair> ret) {
ret.add(
new NameValuePair(name: '[[class]]', value: new ClassMetadata(object)));
}
@@ -389,15 +440,14 @@ class MapFormatter extends ObjectFormatter {
// the build in LinkedHashMap class.
// TODO(jacobr): handle large Maps better.
Map map = object;
- var keys = map.keys.toList();
- var entries = <NameValuePair>[];
+ var entries = new LinkedHashSet<NameValuePair>();
map.forEach((key, value) {
var entryWrapper = new MapEntry(key: key, value: value);
entries.add(new NameValuePair(
name: entries.length.toString(), value: entryWrapper));
});
addMetadataChildren(object, entries);
- return entries;
+ return entries.toList();
}
}
@@ -423,7 +473,7 @@ class IterableFormatter extends ObjectFormatter {
// TODO(jacobr): handle large Iterables better.
// TODO(jacobr): consider only using numeric indices
Iterable iterable = object;
- var ret = <NameValuePair>[];
+ var ret = new LinkedHashSet<NameValuePair>();
var i = 0;
for (var entry in iterable) {
if (i > maxIterableChildrenToDisplay) {
@@ -438,7 +488,7 @@ class IterableFormatter extends ObjectFormatter {
// TODO(jacobr): provide a link to show regular class properties here.
// required for subclasses of iterable, etc.
addMetadataChildren(object, ret);
- return ret;
+ return ret.toList();
}
}
@@ -471,9 +521,9 @@ class ClassMetadataFormatter implements Formatter {
value: new HeritageClause('implements', implements())));
}
var mixins = dart.getMixins(type);
- if (mixins != null) {
+ if (mixins != null && mixins.isNotEmpty) {
ret.add(new NameValuePair(
- name: '[[Mixins]]', value: new HeritageClause('mixins', mixins())));
+ name: '[[Mixins]]', value: new HeritageClause('mixins', mixins)));
}
ret.add(new NameValuePair(
name: '[[JavaScript View]]', value: entry.object, skipDart: true));
« no previous file with comments | « tool/input_sdk/private/ddc_runtime/rtti.dart ('k') | tool/sdk_expected_errors.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698