diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart index 97b14dba82b..1795a14864a 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart @@ -813,6 +813,11 @@ defaultNoSuchMethod(obj, Invocation i) { throw NoSuchMethodError.withInvocation(obj, i); } +// TODO(nshahan) Replace with rti.getRuntimeType() when classes representing +// native types don't have to "pretend" to be Dart classes. Ex: +// JSNumber -> int or double +// JSArray -> List +// NativeFloat32List -> Float32List runtimeType(obj) { return obj == null ? Null : JS('', '#[dartx.runtimeType]', obj); } diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart index e7f8759ca47..ec392377aec 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart @@ -110,6 +110,34 @@ RecordType getRecordType(_RecordImpl obj) { return type; } +/// Returns the interceptor for [obj] as needed by the dart:rti library. +@notNull +Object getInterceptorForRti(obj) { + var classRef; + if (obj == null) { + classRef = JS_CLASS_REF(Null); + } else { + switch (JS('!', 'typeof #', obj)) { + case 'number': + classRef = JS('', 'Math.floor(#) == # ? # : #', obj, obj, + JS_CLASS_REF(JSInt), JS_CLASS_REF(JSNumNotInt)); + break; + case 'function': + var signature = + JS('', '#[#]', obj, JS_GET_NAME(JsGetName.SIGNATURE_NAME)); + if (signature != null) classRef = JS_CLASS_REF(Function); + break; + default: + // The interceptors for native JavaScript types like bool, string, etc. + // (excluding number and function, see above) are stored as a symbolized + // property and can be accessed from the native value itself. + classRef = JS('', '#[#]', obj, _extensionType); + } + } + if (classRef == null) throw 'Unknown interceptor for object: ($obj)'; + return JS('!', '#.prototype', classRef); +} + /// Returns the runtime representation of the type of obj. /// /// The resulting object is used internally for runtime type checking. This is diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart index 9d3b79d41bf..ed957fc4b91 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart @@ -21,12 +21,15 @@ import 'dart:_foreign_helper' spread; import 'dart:_interceptors' show - JSArray, - jsNull, - JSFunction, - NativeError, JavaScriptObject, - LegacyJavaScriptObject; + JSArray, + JSInt, + jsNull, + JSNumNotInt, + JSFunction, + LegacyJavaScriptObject, + NativeError; + import 'dart:_internal' as internal show LateError, Symbol; import 'dart:_js_helper' show diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart index 5d09d5e1dda..feaf99d66a6 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart @@ -89,6 +89,9 @@ void nativeNonNullAsserts(bool enable) { _nativeNonNullAsserts = enable; } +/// A JavaScript Symbol used to store the Rti object on a native array. +final arrayRti = JS('', r'Symbol("$ti")'); + final metadata = JS('', 'Symbol("metadata")'); /// A javascript Symbol used to store a canonical version of T? on T. diff --git a/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart index e7202a7e601..93158376414 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart @@ -7,6 +7,7 @@ library dart._foreign_helper; import 'dart:_interceptors' show JSArray; import 'dart:_js_helper' show notNull; import 'dart:_js_shared_embedded_names' show JsBuiltin, JsGetName; +import 'dart:_runtime' as dart show getInterceptorForRti; import 'dart:_rti' show Rti; /** @@ -299,18 +300,7 @@ external JS_BUILTIN(String typeDescription, JsBuiltin builtin, /// Returns the interceptor for [object]. /// // TODO(nshahan) Replace calls at compile time? -Object getInterceptor(obj) { - var classRef; - if (obj == null) { - classRef = JS_CLASS_REF(Null); - } else if (JS('!', 'typeof #', obj) == 'function') { - var signature = JS('', '#[#]', obj, JS_GET_NAME(JsGetName.SIGNATURE_NAME)); - // Dart functions are always tagged with a signature. - if (signature != null) classRef = JS_CLASS_REF(Function); - } - if (classRef == null) throw 'Unknown interceptor for object: ($obj)'; - return JS('!', '#.prototype', classRef); -} +Object getInterceptor(obj) => dart.getInterceptorForRti(obj); /// Returns the Rti object for the type for JavaScript arrays via JS-interop. /// diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart index 0afc965320d..d8c30ecab9c 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart @@ -7,10 +7,12 @@ library dart._interceptors; import 'dart:collection'; import 'dart:_internal' hide Symbol; import 'dart:_js_helper'; -import 'dart:_foreign_helper' show JS, JS_GET_FLAG, JSExportName; +import 'dart:_foreign_helper' + show JS, JS_EMBEDDED_GLOBAL, JS_GET_FLAG, JSExportName; import 'dart:math' show Random, ln2; import 'dart:_rti' as rti show createRuntimeType, Rti; import 'dart:_runtime' as dart; +import 'dart:_js_shared_embedded_names' show ARRAY_RTI_PROPERTY; part 'js_array.dart'; part 'js_number.dart'; @@ -115,6 +117,7 @@ class UnknownJavaScriptObject extends LegacyJavaScriptObject { const UnknownJavaScriptObject(); } +@JsPeerInterface(name: 'Error') class NativeError extends Interceptor { String dartStack() => JS('!', '#.stack', this); } diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk/lib/_internal/js_dev_runtime/private/js_array.dart index a0ce3d743c6..3ae15ffe30c 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_array.dart @@ -24,6 +24,9 @@ class JSArray implements List, JSIndexable { // TODO(jmesserly): this uses special compiler magic to close over the // parameterized ES6 'JSArray' class. JS('', '#.__proto__ = JSArray.prototype', list); + if (JS_GET_FLAG('NEW_RUNTIME_TYPES')) + JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY), + JSArray); return JS('-dynamic', '#', list); } @@ -31,6 +34,9 @@ class JSArray implements List, JSIndexable { factory JSArray.fixed(list) { JS('', '#.__proto__ = JSArray.prototype', list); JS('', r'#.fixed$length = Array', list); + if (JS_GET_FLAG('NEW_RUNTIME_TYPES')) + JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY), + JSArray); return JS('-dynamic', '#', list); } @@ -38,6 +44,9 @@ class JSArray implements List, JSIndexable { JS('', '#.__proto__ = JSArray.prototype', list); JS('', r'#.fixed$length = Array', list); JS('', r'#.immutable$list = Array', list); + if (JS_GET_FLAG('NEW_RUNTIME_TYPES')) + JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY), + JSArray); return JS('-dynamic', '#', list); } @@ -597,8 +606,7 @@ class JSArray implements List, JSIndexable { return ListMapView(this); } - Type get runtimeType => - dart.wrapType(JS('', '#(#)', dart.getGenericClassStatic(), E)); + Type get runtimeType => List; Iterable followedBy(Iterable other) => FollowedByIterable.firstEfficient(this, other); diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart index 28d1744fed7..573f549ddb5 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart @@ -16,7 +16,7 @@ class JSNumNotInt extends JSNumber implements double {} /// /// These are made available as extension methods on `Number` in JS. @JsPeerInterface(name: 'Number') -class JSNumber extends Interceptor implements int, double { +class JSNumber extends Interceptor implements double { const JSNumber(); @notNull @@ -482,7 +482,7 @@ class JSNumber extends Interceptor implements int, double { return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt(); } - int b = this; + int b = JS('!', '#', this); if (b < 0 || b > m) { b %= m; } @@ -574,7 +574,7 @@ class JSNumber extends Interceptor implements int, double { if (this is! int) throwArgumentErrorValue(this); if (m <= 0) throw RangeError.range(m, 1, null, "modulus"); if (m == 1) return 0; - int t = this; + int t = JS('!', '#', this); if ((t < 0) || (t >= m)) t %= m; if (t == 1) return 1; if ((t == 0) || (t.isEven && m.isEven)) { @@ -587,7 +587,7 @@ class JSNumber extends Interceptor implements int, double { @notNull int gcd(@nullCheck int other) { if (this is! int) throwArgumentErrorValue(this); - int x = this.abs(); + int x = JS('!', '#', this).abs(); int y = other.abs(); if (x == 0) return y; if (y == 0) return x;