| Index: sdk/lib/_internal/js_runtime/lib/js_helper.dart
|
| diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
|
| index 663121a605f99407676a7468c2bd6fe0ce0044ee..000753264a5a14a5d0146b9800c9770b9ec1c2c5 100644
|
| --- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
|
| +++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
|
| @@ -49,6 +49,7 @@ import 'dart:_foreign_helper' show
|
| JS_EMBEDDED_GLOBAL,
|
| JS_GET_FLAG,
|
| JS_GET_NAME,
|
| + JS_INTERCEPTOR_CONSTANT,
|
| JS_STRING_CONCAT,
|
| RAW_DART_FUNCTION_REF;
|
|
|
| @@ -845,24 +846,71 @@ class Primitives {
|
| ///
|
| /// In minified mode, uses the unminified names if available.
|
| static String objectTypeName(Object object) {
|
| - String name = constructorNameFallback(getInterceptor(object));
|
| - if (name == 'Object') {
|
| - // Try to decompile the constructor by turning it into a string and get
|
| - // the name out of that. If the decompiled name is a string containing an
|
| - // identifier, we use that instead of the very generic 'Object'.
|
| - var decompiled =
|
| - JS('var', r'#.match(/^\s*function\s*([\w$]*)\s*\(/)[1]',
|
| - JS('var', r'String(#.constructor)', object));
|
| - if (decompiled is String)
|
| - if (JS('bool', r'/^\w+$/.test(#)', decompiled))
|
| - name = decompiled;
|
| + return formatType(_objectRawTypeName(object), getRuntimeTypeInfo(object));
|
| + }
|
| +
|
| + static String _objectRawTypeName(Object object) {
|
| + var interceptor = getInterceptor(object);
|
| + // The interceptor is either an object (self-intercepting plain Dart class),
|
| + // the prototype of the constructor for an Interceptor class (like
|
| + // `JSString.prototype`, `JSNull.prototype`), or an Interceptor object
|
| + // instance (`const JSString()`, should use `JSString.prototype`).
|
| + //
|
| + // These all should have a `constructor` property with a `name` property.
|
| + String name;
|
| + var interceptorConstructor = JS('', '#.constructor', interceptor);
|
| + if (JS('bool', 'typeof # == "function"', interceptorConstructor)) {
|
| + var interceptorConstructorName = JS('', '#.name', interceptorConstructor);
|
| + if (interceptorConstructorName is String) {
|
| + name = interceptorConstructorName;
|
| + }
|
| + }
|
| +
|
| + if (name == null ||
|
| + identical(interceptor,
|
| + JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject)) ||
|
| + identical(interceptor, JS_INTERCEPTOR_CONSTANT(Interceptor))) {
|
| + // Try to do better. If we do not find something better, leave the name
|
| + // as 'UnknownJavaScriptObject' or 'Interceptor' (or the minified name).
|
| + //
|
| + // When we get here via the UnknownJavaScriptObject test (for JavaScript
|
| + // objects from outside the program), the object's constructor has a
|
| + // better name that 'UnknownJavaScriptObject'.
|
| + //
|
| + // When we get here the Interceptor test (for Native classes that are
|
| + // declared in the Dart program but have been 'folded' into Interceptor),
|
| + // the native class's constructor name is better than the generic
|
| + // 'Interceptor' (an abstract class).
|
| +
|
| + // Try the [constructorNameFallback]. This gets the constructor name for
|
| + // any browser (used by [getNativeInterceptor]).
|
| + String dispatchName = constructorNameFallback(object);
|
| + if (name == null) name = dispatchName;
|
| + if (dispatchName == 'Object') {
|
| + // Try to decompile the constructor by turning it into a string and get
|
| + // the name out of that. If the decompiled name is a string containing
|
| + // an identifier, we use that instead of the very generic 'Object'.
|
| + var objectConstructor = JS('', '#.constructor', object);
|
| + if (JS('bool', 'typeof # == "function"', objectConstructor)) {
|
| + var decompiledName =
|
| + JS('var', r'#.match(/^\s*function\s*([\w$]*)\s*\(/)[1]',
|
| + JS('var', r'String(#)', objectConstructor));
|
| + if (decompiledName is String &&
|
| + JS('bool', r'/^\w+$/.test(#)', decompiledName)) {
|
| + name = decompiledName;
|
| + }
|
| + }
|
| + } else {
|
| + name = dispatchName;
|
| + }
|
| }
|
| +
|
| // TODO(kasperl): If the namer gave us a fresh global name, we may
|
| // want to remove the numeric suffix that makes it unique too.
|
| if (name.length > 1 && identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) {
|
| name = name.substring(1);
|
| }
|
| - return formatType(name, getRuntimeTypeInfo(object));
|
| + return name;
|
| }
|
|
|
| /// In minified mode, uses the unminified names if available.
|
|
|