[dart2js] new-rti: experiment - fault in '$is' test

Change-Id: Ie6d17e3439fb67fe79e9dec4dc7cb5437d1f6915
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121766
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index c797e3b..fd7df4d 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -2571,6 +2571,8 @@
         return asName(fixedNames.deferredAction);
       case JsGetName.OPERATOR_AS_PREFIX:
         return asName(fixedNames.operatorAsPrefix);
+      case JsGetName.OPERATOR_IS_PREFIX:
+        return asName(fixedNames.operatorIsPrefix);
       case JsGetName.SIGNATURE_NAME:
         return asName(fixedNames.operatorSignature);
       case JsGetName.RTI_NAME:
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 30b9964..5a8d3b9 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -109,6 +109,18 @@
     rti._precomputed1 = precomputed;
   }
 
+  // Data value used by some tests.
+  @pragma('dart2js:noElision')
+  Object _specializedTestResource;
+
+  static Object _getSpecializedTestResource(Rti rti) {
+    return rti._specializedTestResource;
+  }
+
+  static void _setSpecializedTestResource(Rti rti, Object value) {
+    rti._specializedTestResource = value;
+  }
+
   // The Type object corresponding to this Rti.
   Object _cachedRuntimeType;
   static _Type _getCachedRuntimeType(Rti rti) =>
@@ -549,6 +561,9 @@
   return result;
 }
 
+bool _isDartObject(object) => _Utils.instanceOf(object,
+    JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+
 bool _isClosure(object) => _Utils.instanceOf(object,
     JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartClosureConstructor));
 
@@ -597,10 +612,7 @@
   // called, similar to a one-shot interceptor call. This would improve type
   // lookup in ListMixin code as the interceptor is JavaScript 'this'.
 
-  if (_Utils.instanceOf(
-      object,
-      JS_BUILTIN(
-          'depends:none;effects:none;', JsBuiltin.dartObjectConstructor))) {
+  if (_isDartObject(object)) {
     return _instanceType(object);
   }
 
@@ -762,6 +774,16 @@
       isFn = RAW_DART_FUNCTION_REF(_isString);
     } else if (JS_GET_NAME(JsGetName.BOOL_RECIPE) == key) {
       isFn = RAW_DART_FUNCTION_REF(_isBool);
+    } else {
+      String name = Rti._getInterfaceName(testRti);
+      var arguments = Rti._getInterfaceTypeArguments(testRti);
+      if (JS(
+          'bool', '#.every(#)', arguments, RAW_DART_FUNCTION_REF(isTopType))) {
+        String propertyName =
+            '${JS_GET_NAME(JsGetName.OPERATOR_IS_PREFIX)}${name}';
+        Rti._setSpecializedTestResource(testRti, propertyName);
+        isFn = RAW_DART_FUNCTION_REF(_isTestViaProperty);
+      }
     }
   }
 
@@ -779,6 +801,24 @@
 }
 
 /// Called from generated code.
+bool _isTestViaProperty(object) {
+  // This static method is installed on an Rti object as a JavaScript instance
+  // method. The Rti object is 'this'.
+  Rti testRti = _castToRti(JS('', 'this'));
+  var tag = Rti._getSpecializedTestResource(testRti);
+
+  // This test is redundant with getInterceptor below, but getInterceptor does
+  // the tests in the wrong order for most tags, so it is usually faster to have
+  // this check.
+  if (_isDartObject(object)) {
+    return JS('bool', '!!#[#]', object, tag);
+  }
+
+  var interceptor = getInterceptor(object);
+  return JS('bool', '!!#[#]', interceptor, tag);
+}
+
+/// Called from generated code.
 _generalAsCheckImplementation(object) {
   if (object == null) return object;
   // This static method is installed on an Rti object as a JavaScript instance
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
index 2b00f2f..9b9e648 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -111,6 +111,18 @@
     rti._precomputed1 = precomputed;
   }
 
+  // Data value used by some tests.
+  @pragma('dart2js:noElision')
+  Object _specializedTestResource;
+
+  static Object _getSpecializedTestResource(Rti rti) {
+    return rti._specializedTestResource;
+  }
+
+  static void _setSpecializedTestResource(Rti rti, Object value) {
+    rti._specializedTestResource = value;
+  }
+
   // The Type object corresponding to this Rti.
   Object _cachedRuntimeType;
   static _Type _getCachedRuntimeType(Rti rti) =>
@@ -551,6 +563,9 @@
   return result;
 }
 
+bool _isDartObject(object) => _Utils.instanceOf(object,
+    JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+
 bool _isClosure(object) => _Utils.instanceOf(object,
     JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartClosureConstructor));
 
@@ -599,10 +614,7 @@
   // called, similar to a one-shot interceptor call. This would improve type
   // lookup in ListMixin code as the interceptor is JavaScript 'this'.
 
-  if (_Utils.instanceOf(
-      object,
-      JS_BUILTIN(
-          'depends:none;effects:none;', JsBuiltin.dartObjectConstructor))) {
+  if (_isDartObject(object)) {
     return _instanceType(object);
   }
 
@@ -764,6 +776,16 @@
       isFn = RAW_DART_FUNCTION_REF(_isString);
     } else if (JS_GET_NAME(JsGetName.BOOL_RECIPE) == key) {
       isFn = RAW_DART_FUNCTION_REF(_isBool);
+    } else {
+      String name = Rti._getInterfaceName(testRti);
+      var arguments = Rti._getInterfaceTypeArguments(testRti);
+      if (JS(
+          'bool', '#.every(#)', arguments, RAW_DART_FUNCTION_REF(isTopType))) {
+        String propertyName =
+            '${JS_GET_NAME(JsGetName.OPERATOR_IS_PREFIX)}${name}';
+        Rti._setSpecializedTestResource(testRti, propertyName);
+        isFn = RAW_DART_FUNCTION_REF(_isTestViaProperty);
+      }
     }
   }
 
@@ -781,6 +803,24 @@
 }
 
 /// Called from generated code.
+bool _isTestViaProperty(object) {
+  // This static method is installed on an Rti object as a JavaScript instance
+  // method. The Rti object is 'this'.
+  Rti testRti = _castToRti(JS('', 'this'));
+  var tag = Rti._getSpecializedTestResource(testRti);
+
+  // This test is redundant with getInterceptor below, but getInterceptor does
+  // the tests in the wrong order for most tags, so it is usually faster to have
+  // this check.
+  if (_isDartObject(object)) {
+    return JS('bool', '!!#[#]', object, tag);
+  }
+
+  var interceptor = getInterceptor(object);
+  return JS('bool', '!!#[#]', interceptor, tag);
+}
+
+/// Called from generated code.
 _generalAsCheckImplementation(object) {
   if (object == null) return object;
   // This static method is installed on an Rti object as a JavaScript instance