[dart2wasm] Optimize dartify type-checks

dartifyRaw type-checks are currently a bunch of if
cases where the check is done in JS. Instead of going
back and forth between runtimes, we can do the checks
in JS and return an enum value.

- Replaces the if cases with a externRefType method that
returns an integer that maps to some static const values.
Dart enums are slower so consts are preferred. Speeds up
type-checks by 4-5x and dartifyRaw by 1.1-1.8x for common
types using some quick local benchmarks. Also moves the
array check up as it's more common and groups the typed
array checks together.
- Reuses the externRefType helper in dartify so we don't
type-check the same value twice.
- Moves some tests from basic_test.dart to jsify_dartify_test.dart
and adds more type-checks, casts to assert types, cleans
up property getters, and adds a few missing cases.

Change-Id: Ia5fb9bfef6f9e212ea8da27362b0b4efb4cbf2fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/379144
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/sdk/lib/_internal/wasm/lib/js_helper.dart b/sdk/lib/_internal/wasm/lib/js_helper.dart
index 956ccd9..64b46cd 100644
--- a/sdk/lib/_internal/wasm/lib/js_helper.dart
+++ b/sdk/lib/_internal/wasm/lib/js_helper.dart
@@ -387,46 +387,104 @@
 
 bool isWasmGCStruct(WasmExternRef? ref) => ref.internalize()?.isObject ?? false;
 
-Object? dartifyRaw(WasmExternRef? ref) {
-  if (ref.isNull || isJSUndefined(ref)) {
-    return null;
-  } else if (isJSBoolean(ref)) {
-    return toDartBool(ref);
-  } else if (isJSNumber(ref)) {
-    return toDartNumber(ref);
-  } else if (isJSString(ref)) {
-    return JSStringImpl.box(ref);
-  } else if (isJSInt8Array(ref)) {
-    return js_types.JSInt8ArrayImpl.fromJSArray(ref);
-  } else if (isJSUint8Array(ref)) {
-    return js_types.JSUint8ArrayImpl.fromJSArray(ref);
-  } else if (isJSUint8ClampedArray(ref)) {
-    return js_types.JSUint8ClampedArrayImpl.fromJSArray(ref);
-  } else if (isJSInt16Array(ref)) {
-    return js_types.JSInt16ArrayImpl.fromJSArray(ref);
-  } else if (isJSUint16Array(ref)) {
-    return js_types.JSUint16ArrayImpl.fromJSArray(ref);
-  } else if (isJSInt32Array(ref)) {
-    return js_types.JSInt32ArrayImpl.fromJSArray(ref);
-  } else if (isJSUint32Array(ref)) {
-    return js_types.JSUint32ArrayImpl.fromJSArray(ref);
-  } else if (isJSFloat32Array(ref)) {
-    return js_types.JSFloat32ArrayImpl.fromJSArray(ref);
-  } else if (isJSFloat64Array(ref)) {
-    return js_types.JSFloat64ArrayImpl.fromJSArray(ref);
-  } else if (isJSArrayBuffer(ref)) {
-    return js_types.JSArrayBufferImpl.fromRef(ref);
-  } else if (isJSDataView(ref)) {
-    return js_types.JSDataViewImpl.fromRef(ref);
-  } else if (isJSArray(ref)) {
-    return toDartList(ref);
-  } else if (isJSWrappedDartFunction(ref)) {
-    return unwrapJSWrappedDartFunction(ref);
-  } else if (isWasmGCStruct(ref)) {
-    return jsObjectToDartObject(ref);
-  } else {
-    return JSValue(ref);
+/// Container class for constants that represent the possible types of a
+/// [WasmExternRef] that can then be used in a [dartifyRaw] call.
+///
+/// The values within this class should correspond to the values returned by
+/// [externRefType] and should be updated if that function is updated. Constants
+/// are preferred over enums for performance.
+class ExternRefType {
+  static const int null_ = 0;
+  static const int undefined = 1;
+  static const int boolean = 2;
+  static const int number = 3;
+  static const int string = 4;
+  static const int array = 5;
+  static const int int8Array = 6;
+  static const int uint8Array = 7;
+  static const int uint8ClampedArray = 8;
+  static const int int16Array = 9;
+  static const int uint16Array = 10;
+  static const int int32Array = 11;
+  static const int uint32Array = 12;
+  static const int float32Array = 13;
+  static const int float64Array = 14;
+  static const int dataView = 15;
+  static const int arrayBuffer = 16;
+  static const int unknown = 17;
+}
+
+/// Returns an integer representing the type of [ref] that corresponds to one of
+/// the constant values in [ExternRefType].
+///
+/// If this function is updated to return different values, [ExternRefType]
+/// should be updated as well.
+int externRefType(WasmExternRef? ref) {
+  if (ref.isNull) return ExternRefType.null_;
+  final val = JS<WasmI32>('''
+  o => {
+    if (o === undefined) return 1;
+    var type = typeof o;
+    if (type === 'boolean') return 2;
+    if (type === 'number') return 3;
+    if (type === 'string') return 4;
+    if (o instanceof Array) return 5;
+    if (ArrayBuffer.isView(o)) {
+      if (o instanceof Int8Array) return 6;
+      if (o instanceof Uint8Array) return 7;
+      if (o instanceof Uint8ClampedArray) return 8;
+      if (o instanceof Int16Array) return 9;
+      if (o instanceof Uint16Array) return 10;
+      if (o instanceof Int32Array) return 11;
+      if (o instanceof Uint32Array) return 12;
+      if (o instanceof Float32Array) return 13;
+      if (o instanceof Float64Array) return 14;
+      if (o instanceof DataView) return 15;
+    }
+    if (o instanceof ArrayBuffer) return 16;
+    return 17;
   }
+  ''', ref).toIntUnsigned();
+  return val;
+}
+
+/// Non-recursively converts [ref] from a JS value to a Dart value for some JS
+/// types.
+///
+/// If [refType] is not null, it is treated as one of the values from
+/// [ExternRefType]. Otherwise, this method calls [externRefType] to determine
+/// the right [ExternRefType].
+Object? dartifyRaw(WasmExternRef? ref, [int? refType]) {
+  refType ??= externRefType(ref);
+  return switch (refType) {
+    ExternRefType.null_ || ExternRefType.undefined => null,
+    ExternRefType.boolean => toDartBool(ref),
+    ExternRefType.number => toDartNumber(ref),
+    ExternRefType.string => JSStringImpl.box(ref),
+    ExternRefType.array => toDartList(ref),
+    ExternRefType.int8Array => js_types.JSInt8ArrayImpl.fromJSArray(ref),
+    ExternRefType.uint8Array => js_types.JSUint8ArrayImpl.fromJSArray(ref),
+    ExternRefType.uint8ClampedArray =>
+      js_types.JSUint8ClampedArrayImpl.fromJSArray(ref),
+    ExternRefType.int16Array => js_types.JSInt16ArrayImpl.fromJSArray(ref),
+    ExternRefType.uint16Array => js_types.JSUint16ArrayImpl.fromJSArray(ref),
+    ExternRefType.int32Array => js_types.JSInt32ArrayImpl.fromJSArray(ref),
+    ExternRefType.uint32Array => js_types.JSUint32ArrayImpl.fromJSArray(ref),
+    ExternRefType.float32Array => js_types.JSFloat32ArrayImpl.fromJSArray(ref),
+    ExternRefType.float64Array => js_types.JSFloat64ArrayImpl.fromJSArray(ref),
+    ExternRefType.arrayBuffer => js_types.JSArrayBufferImpl.fromRef(ref),
+    ExternRefType.dataView => js_types.JSDataViewImpl.fromRef(ref),
+    ExternRefType.unknown => isJSWrappedDartFunction(ref)
+        ? unwrapJSWrappedDartFunction(ref)
+        : isWasmGCStruct(ref)
+            ? jsObjectToDartObject(ref)
+            : JSValue(ref),
+    _ => () {
+        // Assert that we've handled everything in the range.
+        assert(refType! >= 0 && refType >= ExternRefType.unknown);
+        throw 'Unhandled dartifyRaw type case: $refType';
+      }()
+  };
 }
 
 Int8List toDartInt8List(WasmExternRef? ref) =>
diff --git a/sdk/lib/_internal/wasm/lib/js_util_patch.dart b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
index ea892ff..f7e1581 100644
--- a/sdk/lib/_internal/wasm/lib/js_util_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
@@ -191,8 +191,7 @@
 
 @patch
 List<Object?> objectKeys(Object? o) =>
-    dartifyRaw(JS<WasmExternRef?>('o => Object.keys(o)', jsifyRaw(o)))
-        as List<Object?>;
+    toDartList(JS<WasmExternRef?>('o => Object.keys(o)', jsifyRaw(o)));
 
 @patch
 Object? dartify(Object? object) {
@@ -201,7 +200,6 @@
     if (convertedObjects.containsKey(o)) {
       return convertedObjects[o];
     }
-
     // Because [List] needs to be shallowly converted across the interop
     // boundary, we have to double check for the case where a shallowly
     // converted [List] is passed back into [dartify].
@@ -212,37 +210,11 @@
       }
       return converted;
     }
-
-    if (o is! JSValue) {
-      return o;
-    }
-
+    if (o is! JSValue) return o;
     WasmExternRef? ref = o.toExternRef;
-    if (ref.isNull ||
-        isJSBoolean(ref) ||
-        isJSNumber(ref) ||
-        isJSString(ref) ||
-        isJSUndefined(ref) ||
-        isJSBoolean(ref) ||
-        isJSNumber(ref) ||
-        isJSString(ref) ||
-        isJSInt8Array(ref) ||
-        isJSUint8Array(ref) ||
-        isJSUint8ClampedArray(ref) ||
-        isJSInt16Array(ref) ||
-        isJSUint16Array(ref) ||
-        isJSInt32Array(ref) ||
-        isJSUint32Array(ref) ||
-        isJSFloat32Array(ref) ||
-        isJSFloat64Array(ref) ||
-        isJSArrayBuffer(ref) ||
-        isJSDataView(ref)) {
-      return dartifyRaw(ref);
-    }
-
+    final refType = externRefType(ref);
     // TODO(joshualitt) handle Date and Promise.
-
-    if (isJSSimpleObject(ref)) {
+    if (refType == ExternRefType.unknown && isJSSimpleObject(ref)) {
       final dartMap = <Object?, Object?>{};
       convertedObjects[o] = dartMap;
       // Keys will be a list of Dart [String]s.
@@ -255,7 +227,8 @@
         }
       }
       return dartMap;
-    } else if (isJSArray(ref)) {
+    }
+    if (refType == ExternRefType.array) {
       final dartList = <Object?>[];
       convertedObjects[o] = dartList;
       final length = getProperty<double>(o, 'length').toInt();
@@ -263,9 +236,8 @@
         dartList.add(convert(JSValue.box(objectReadIndex(ref, i))));
       }
       return dartList;
-    } else {
-      return dartifyRaw(ref);
     }
+    return dartifyRaw(ref, refType);
   }
 
   return convert(object);
diff --git a/tests/lib/js/static_interop_test/jsify_dartify_test.dart b/tests/lib/js/static_interop_test/jsify_dartify_test.dart
new file mode 100644
index 0000000..49d936e
--- /dev/null
+++ b/tests/lib/js/static_interop_test/jsify_dartify_test.dart
@@ -0,0 +1,240 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:js_interop';
+import 'dart:js_interop_unsafe';
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+void _expectIterableEquals(Iterable<Object?> l, Iterable<Object?> r) {
+  final lIt = l.iterator;
+  final rIt = r.iterator;
+  while (lIt.moveNext()) {
+    Expect.isTrue(rIt.moveNext());
+    _expectRecEquals(lIt.current, rIt.current);
+  }
+  Expect.isFalse(rIt.moveNext());
+}
+
+void _expectRecEquals(Object? l, Object? r) {
+  if (l is Iterable && r is Iterable) {
+    _expectIterableEquals(l, r);
+  } else if (l is Map && r is Map) {
+    _expectIterableEquals(l.keys, r.keys);
+    for (final key in l.keys) {
+      _expectRecEquals(l[key], r[key]);
+    }
+  } else {
+    Expect.equals(l, r);
+  }
+}
+
+@JS()
+external void eval(String code);
+
+void main() {
+  // Dart to JS.
+  Expect.isNull(null.jsify().dartify());
+  Expect.isTrue(true.jsify().isA<JSBoolean>());
+  Expect.equals(true, true.jsify().dartify() as bool);
+  Expect.isTrue(2.0.jsify().isA<JSNumber>());
+  Expect.equals(2.0, 2.0.jsify().dartify() as double);
+  Expect.isTrue(0.jsify().isA<JSNumber>());
+  Expect.equals(0.0, 0.jsify().dartify() as double);
+  Expect.isTrue('foo'.jsify().isA<JSString>());
+  Expect.equals('foo', 'foo'.jsify().dartify() as String);
+  List<Object?> l = ['a', 'b', 'c'];
+  Expect.isTrue(l.jsify().isA<JSArray>());
+  _expectRecEquals(l, l.jsify().dartify() as List<Object?>);
+  _expectRecEquals(
+      {
+        'null': 'foo',
+        'foo': null,
+        'a': 1,
+        'b': true,
+        'c': [1, 2, 3, null],
+        'd': 'foo',
+        'e': {
+          'f': 2,
+          'g': [2, 4, 6]
+        },
+      },
+      {
+        'null': 'foo',
+        'foo': null,
+        'a': 1,
+        'b': true,
+        'c': [1, 2, 3, null],
+        'd': 'foo',
+        'e': {
+          'f': 2,
+          'g': [2, 4, 6]
+        },
+      }.jsify().dartify());
+  l = Int8List.fromList(<int>[-128, 0, 127]);
+  Expect.isTrue(l.jsify().isA<JSInt8Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Int8List);
+  l = Uint8List.fromList([-1, 0, 255, 256]);
+  Expect.isTrue(l.jsify().isA<JSUint8Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Uint8List);
+  l = Uint8ClampedList.fromList([-1, 0, 255, 256]);
+  Expect.isTrue(l.jsify().isA<JSUint8ClampedArray>());
+  _expectIterableEquals(l, l.jsify().dartify() as Uint8ClampedList);
+  l = Int16List.fromList([-32769, -32768, 0, 32767, 32768]);
+  Expect.isTrue(l.jsify().isA<JSInt16Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Int16List);
+  l = Uint16List.fromList([-1, 0, 65535, 65536]);
+  Expect.isTrue(l.jsify().isA<JSUint16Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Uint16List);
+  l = Int32List.fromList([-2147483648, 0, 2147483647]);
+  Expect.isTrue(l.jsify().isA<JSInt32Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Int32List);
+  l = Uint32List.fromList([-1, 0, 4294967295, 4294967296]);
+  Expect.isTrue(l.jsify().isA<JSUint32Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Uint32List);
+  l = Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
+  Expect.isTrue(l.jsify().isA<JSFloat32Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Float32List);
+  l = Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
+  Expect.isTrue(l.jsify().isA<JSFloat64Array>());
+  _expectIterableEquals(l, l.jsify().dartify() as Float64List);
+  ByteBuffer buffer = Uint8List.fromList([0, 1, 2, 3]).buffer;
+  Expect.isTrue(buffer.jsify().isA<JSArrayBuffer>());
+  _expectIterableEquals(buffer.asUint8List(),
+      (buffer.jsify().dartify() as ByteBuffer).asUint8List());
+  ByteData byteData = ByteData.view(buffer);
+  Expect.isTrue(byteData.jsify().isA<JSDataView>());
+  _expectIterableEquals(byteData.buffer.asUint8List(),
+      (byteData.jsify().dartify() as ByteData).buffer.asUint8List());
+
+  // JS to Dart.
+  eval(r'''
+    globalThis.a = null;
+    globalThis.b = undefined;
+    globalThis.c = 'foo';
+    globalThis.d = ['a', 'b', 'c'];
+    globalThis.e = 2.5;
+    globalThis.f = true;
+    globalThis.g = function () { return 'hello world'; };
+    globalThis.h = {
+        null: 'foo',
+        'foo': null,
+        'a': 1,
+        'b': true,
+        'c': [1, 2, 3, null],
+        'd': 'foo',
+        'e': {'f': 2, 'g': [2, 4, 6]},
+      };
+    globalThis.invoke = function (f) { return f(); }
+    globalThis.rec = {};
+    globalThis.rec = {'a': rec};
+    globalThis.int8Array = new Int8Array([-128, 0, 127]);
+    globalThis.uint8Array = new Uint8Array([-1, 0, 255, 256]);
+    globalThis.uint8ClampedArray = new Uint8ClampedArray([-1, 0, 255, 256]);
+    globalThis.int16Array = new Int16Array([-32769, -32768, 0, 32767, 32768]);
+    globalThis.uint16Array = new Uint16Array([-1, 0, 65535, 65536]);
+    globalThis.int32Array = new Int32Array([-2147483648, 0, 2147483647]);
+    globalThis.uint32Array = new Uint32Array([-1, 0, 4294967295, 4294967296]);
+    globalThis.float32Array = new Float32Array([-1000.488, -0.00001, 0.0001,
+        10004.888]);
+    globalThis.float64Array = new Float64Array([-1000.488, -0.00001, 0.0001,
+        10004.888]);
+    globalThis.arrayBuffer = globalThis.uint8Array.buffer;
+    globalThis.dataView = new DataView(globalThis.arrayBuffer);
+    globalThis.implicitExplicit = [
+      {'foo': 'bar'},
+      [1, 2, 3, {'baz': 'boo'}],
+    ];
+    let keyObject = function () {};
+    globalThis.keyObject1 = keyObject;
+    globalThis.keyObject2 = keyObject;
+    globalThis.symbol = Symbol('symbol');
+  ''');
+  JSObject gc = globalContext;
+  Expect.isNull(gc['a']);
+  Expect.isNull(gc['b']);
+  Expect.equals('foo', gc['c'].dartify() as String);
+  _expectRecEquals(['a', 'b', 'c'], gc['d'].dartify() as List<Object?>);
+  Expect.equals(2.5, gc['e'].dartify() as double);
+  Expect.equals(true, gc['f'].dartify() as bool);
+  _expectRecEquals({
+    'null': 'foo',
+    'foo': null,
+    'a': 1,
+    'b': true,
+    'c': [1, 2, 3, null],
+    'd': 'foo',
+    'e': {
+      'f': 2,
+      'g': [2, 4, 6]
+    },
+  }, gc['h'].dartify() as Map<Object?, Object?>);
+  _expectRecEquals({
+    'a': {},
+  }, gc['rec'].dartify() as Map<Object?, Object?>);
+
+  _expectIterableEquals(Int8List.fromList(<int>[-128, 0, 127]),
+      gc['int8Array'].dartify() as Int8List);
+  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
+      gc['uint8Array'].dartify() as Uint8List);
+  _expectIterableEquals(Uint8ClampedList.fromList([-1, 0, 255, 256]),
+      gc['uint8ClampedArray'].dartify() as Uint8ClampedList);
+  _expectIterableEquals(Int16List.fromList([-32769, -32768, 0, 32767, 32768]),
+      gc['int16Array'].dartify() as Int16List);
+  _expectIterableEquals(Uint16List.fromList([-1, 0, 65535, 65536]),
+      gc['uint16Array'].dartify() as Uint16List);
+  _expectIterableEquals(Int32List.fromList([-2147483648, 0, 2147483647]),
+      gc['int32Array'].dartify() as Int32List);
+  _expectIterableEquals(Uint32List.fromList([-1, 0, 4294967295, 4294967296]),
+      gc['uint32Array'].dartify() as Uint32List);
+  _expectIterableEquals(
+      Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
+      gc['float32Array'].dartify() as Float32List);
+  _expectIterableEquals(
+      Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
+      gc['float64Array'].dartify() as Float64List);
+  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
+      (gc['arrayBuffer'].dartify() as ByteBuffer).asUint8List());
+  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
+      (gc['dataView'].dartify() as ByteData).buffer.asUint8List());
+
+  // Confirm a function that takes a roundtrip remains a function.
+  // TODO(srujzs): Delete this test after we remove this conversion.
+  JSFunction foo = gc['g'].dartify() as JSFunction;
+  Expect.equals(
+      'hello world', gc.callMethod<JSString>('invoke'.toJS, foo).toDart);
+
+  // Confirm arrays, which need to be converted implicitly, are still
+  // recursively converted by dartify() when desired.
+  _expectIterableEquals([
+    {'foo': 'bar'},
+    [
+      1,
+      2,
+      3,
+      {'baz': 'boo'}
+    ],
+  ], gc['implicitExplicit'].dartify() as List<Object?>);
+
+  // Test that JS objects behave as expected in Map / Set.
+  Set<Object?> set = {};
+  JSAny? key1 = gc['keyObject1'];
+  JSAny? key2 = gc['keyObject2'];
+  Expect.isTrue(set.add(key1));
+  Expect.isTrue(set.contains(key1));
+  Expect.isFalse(set.add(key2));
+  Expect.isTrue(set.contains(key2));
+  Expect.equals(1, set.length);
+
+  Map<Object?, Object?> map = {};
+  map[key1] = 'foo';
+  map[key2] = 'bar';
+  Expect.equals(1, map.length);
+  Expect.equals('bar', map[key1]);
+
+  // Test that unrelated values are left alone/simply boxed.
+  Expect.isTrue((gc['symbol'].dartify() as JSAny).isA<JSSymbol>());
+  Expect.equals(gc['symbol'], gc['symbol'].dartify());
+}
diff --git a/tests/lib/js_interop_unsafe/basic_test.dart b/tests/lib/js_interop_unsafe/basic_test.dart
index adf341d..d98dd68 100644
--- a/tests/lib/js_interop_unsafe/basic_test.dart
+++ b/tests/lib/js_interop_unsafe/basic_test.dart
@@ -139,29 +139,6 @@
   Expect.isFalse(0.toJS.instanceOfString('JSClass1'));
 }
 
-void _expectIterableEquals(Iterable<Object?> l, Iterable<Object?> r) {
-  final lIt = l.iterator;
-  final rIt = r.iterator;
-  while (lIt.moveNext()) {
-    Expect.isTrue(rIt.moveNext());
-    _expectRecEquals(lIt.current, rIt.current);
-  }
-  Expect.isFalse(rIt.moveNext());
-}
-
-void _expectRecEquals(Object? l, Object? r) {
-  if (l is Iterable && r is Iterable) {
-    _expectIterableEquals(l, r);
-  } else if (l is Map && r is Map) {
-    _expectIterableEquals(l.keys, r.keys);
-    for (final key in l.keys) {
-      _expectRecEquals(l[key], r[key]);
-    }
-  } else {
-    Expect.equals(l, r);
-  }
-}
-
 void methodsAndConstructorsTest() {
   eval(r'''
     function JSClass(c) {
@@ -214,191 +191,6 @@
   Expect.equals(jsObj1['c'], null);
 }
 
-void deepConversionsTest() {
-  // Dart to JS.
-  Expect.isNull(null.jsify().dartify());
-  Expect.equals(true, true.jsify().dartify());
-  Expect.equals(2.0, 2.0.jsify().dartify());
-  Expect.equals('foo', 'foo'.jsify().dartify());
-  _expectRecEquals(
-      ['a', 'b', 'c'], ['a', 'b', 'c'].jsify().dartify() as List<Object?>);
-  _expectRecEquals(
-      {
-        'null': 'foo',
-        'foo': null,
-        'a': 1,
-        'b': true,
-        'c': [1, 2, 3, null],
-        'd': 'foo',
-        'e': {
-          'f': 2,
-          'g': [2, 4, 6]
-        },
-      },
-      {
-        'null': 'foo',
-        'foo': null,
-        'a': 1,
-        'b': true,
-        'c': [1, 2, 3, null],
-        'd': 'foo',
-        'e': {
-          'f': 2,
-          'g': [2, 4, 6]
-        },
-      }.jsify().dartify());
-  List<Object?> l = Int8List.fromList(<int>[-128, 0, 127]);
-  _expectIterableEquals(l, l.jsify().dartify() as Int8List);
-  l = Uint8List.fromList([-1, 0, 255, 256]);
-  _expectIterableEquals(l, l.jsify().dartify() as Uint8List);
-  l = Uint8ClampedList.fromList([-1, 0, 255, 256]);
-  _expectIterableEquals(l, l.jsify().dartify() as Uint8ClampedList);
-  l = Int16List.fromList([-32769, -32768, 0, 32767, 32768]);
-  _expectIterableEquals(l, l.jsify().dartify() as Int16List);
-  l = Uint16List.fromList([-1, 0, 65535, 65536]);
-  _expectIterableEquals(l, l.jsify().dartify() as Uint16List);
-  l = Int32List.fromList([-2147483648, 0, 2147483647]);
-  _expectIterableEquals(l, l.jsify().dartify() as Int32List);
-  l = Uint32List.fromList([-1, 0, 4294967295, 4294967296]);
-  _expectIterableEquals(l, l.jsify().dartify() as Uint32List);
-  l = Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
-  _expectIterableEquals(l, l.jsify().dartify() as Float32List);
-  l = Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
-  _expectIterableEquals(l, l.jsify().dartify() as Float64List);
-  ByteBuffer buffer = Uint8List.fromList([0, 1, 2, 3]).buffer;
-  _expectIterableEquals(buffer.asUint8List(),
-      (buffer.jsify().dartify() as ByteBuffer).asUint8List());
-  ByteData byteData = ByteData.view(buffer);
-  _expectIterableEquals(byteData.buffer.asUint8List(),
-      (byteData.jsify().dartify() as ByteData).buffer.asUint8List());
-
-  // JS to Dart.
-  eval(r'''
-    globalThis.a = null;
-    globalThis.b = 'foo';
-    globalThis.c = ['a', 'b', 'c'];
-    globalThis.d = 2.5;
-    globalThis.e = true;
-    globalThis.f = function () { return 'hello world'; };
-    globalThis.g = {
-        null: 'foo',
-        'foo': null,
-        'a': 1,
-        'b': true,
-        'c': [1, 2, 3, null],
-        'd': 'foo',
-        'e': {'f': 2, 'g': [2, 4, 6]},
-      };
-    globalThis.invoke = function (f) { return f(); }
-    globalThis.rec = {};
-    globalThis.rec = {'a': rec};
-    globalThis.int8Array = new Int8Array([-128, 0, 127]);
-    globalThis.uint8Array = new Uint8Array([-1, 0, 255, 256]);
-    globalThis.uint8ClampedArray = new Uint8ClampedArray([-1, 0, 255, 256]);
-    globalThis.int16Array = new Int16Array([-32769, -32768, 0, 32767, 32768]);
-    globalThis.uint16Array = new Uint16Array([-1, 0, 65535, 65536]);
-    globalThis.int32Array = new Int32Array([-2147483648, 0, 2147483647]);
-    globalThis.uint32Array = new Uint32Array([-1, 0, 4294967295, 4294967296]);
-    globalThis.float32Array = new Float32Array([-1000.488, -0.00001, 0.0001,
-        10004.888]);
-    globalThis.float64Array = new Float64Array([-1000.488, -0.00001, 0.0001,
-        10004.888]);
-    globalThis.arrayBuffer = globalThis.uint8Array.buffer;
-    globalThis.dataView = new DataView(globalThis.arrayBuffer);
-    globalThis.implicitExplicit = [
-      {'foo': 'bar'},
-      [1, 2, 3, {'baz': 'boo'}],
-    ];
-    let keyObject = function () {};
-    globalThis.keyObject1 = keyObject;
-    globalThis.keyObject2 = keyObject;
-  ''');
-  JSObject gc = globalContext;
-  Expect.isNull(gc['a']);
-  Expect.equals('foo', gc.getProperty<JSString>('b'.toJS).toDart);
-  _expectRecEquals(
-      ['a', 'b', 'c'],
-      gc
-          .getProperty<JSArray>('c'.toJS)
-          .toDart
-          .map((JSAny? o) => (o as JSString).toDart));
-  Expect.equals(2.5, gc.getProperty<JSNumber>('d'.toJS).toDartDouble);
-  Expect.equals(true, gc.getProperty<JSBoolean>('e'.toJS).toDart);
-  _expectRecEquals({
-    'null': 'foo',
-    'foo': null,
-    'a': 1,
-    'b': true,
-    'c': [1, 2, 3, null],
-    'd': 'foo',
-    'e': {
-      'f': 2,
-      'g': [2, 4, 6]
-    },
-  }, gc.getProperty('g'.toJS).dartify());
-  _expectRecEquals({
-    'a': {},
-  }, gc.getProperty('rec'.toJS).dartify());
-
-  _expectIterableEquals(Int8List.fromList(<int>[-128, 0, 127]),
-      gc.getProperty<JSInt8Array>('int8Array'.toJS).toDart);
-  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
-      gc.getProperty<JSUint8Array>('uint8Array'.toJS).toDart);
-  _expectIterableEquals(Uint8ClampedList.fromList([-1, 0, 255, 256]),
-      gc.getProperty<JSUint8ClampedArray>('uint8ClampedArray'.toJS).toDart);
-  _expectIterableEquals(Int16List.fromList([-32769, -32768, 0, 32767, 32768]),
-      gc.getProperty<JSInt16Array>('int16Array'.toJS).toDart);
-  _expectIterableEquals(Uint16List.fromList([-1, 0, 65535, 65536]),
-      gc.getProperty<JSUint16Array>('uint16Array'.toJS).toDart);
-  _expectIterableEquals(Int32List.fromList([-2147483648, 0, 2147483647]),
-      gc.getProperty<JSInt32Array>('int32Array'.toJS).toDart);
-  _expectIterableEquals(Uint32List.fromList([-1, 0, 4294967295, 4294967296]),
-      gc.getProperty<JSUint32Array>('uint32Array'.toJS).toDart);
-  _expectIterableEquals(
-      Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
-      gc.getProperty<JSFloat32Array>('float32Array'.toJS).toDart);
-  _expectIterableEquals(
-      Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
-      gc.getProperty<JSFloat64Array>('float64Array'.toJS).toDart);
-  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
-      gc.getProperty<JSArrayBuffer>('arrayBuffer'.toJS).toDart.asUint8List());
-  _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
-      gc.getProperty<JSDataView>('dataView'.toJS).toDart.buffer.asUint8List());
-
-  // Confirm a function that takes a roundtrip remains a function.
-  JSFunction foo = gc['f'].dartify() as JSFunction;
-  Expect.equals(
-      'hello world', gc.callMethod<JSString>('invoke'.toJS, foo).toDart);
-
-  // Confirm arrays, which need to be converted implicitly, are still
-  // recursively converted by dartify() when desired.
-  _expectIterableEquals([
-    {'foo': 'bar'},
-    [
-      1,
-      2,
-      3,
-      {'baz': 'boo'}
-    ],
-  ], gc['implicitExplicit'].dartify() as Iterable);
-
-  // Test that JS objects behave as expected in Map / Set.
-  Set<Object?> set = {};
-  JSAny? key1 = gc['keyObject1'];
-  JSAny? key2 = gc['keyObject2'];
-  Expect.isTrue(set.add(key1));
-  Expect.isTrue(set.contains(key1));
-  Expect.isFalse(set.add(key2));
-  Expect.isTrue(set.contains(key2));
-  Expect.equals(1, set.length);
-
-  Map<Object?, Object?> map = {};
-  map[key1] = 'foo';
-  map[key2] = 'bar';
-  Expect.equals(1, map.length);
-  Expect.equals('bar', map[key1]);
-}
-
 @JS('Symbol')
 @staticInterop
 class _JSSymbol {
@@ -449,6 +241,5 @@
   typeofTest();
   instanceOfTest();
   methodsAndConstructorsTest();
-  deepConversionsTest();
   symbolTest();
 }
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 84d5a2e..06259c5 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -93,6 +93,7 @@
 js/static_interop_test/js_function_arity_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
 js/static_interop_test/js_function_conversions_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
 js/static_interop_test/js_typed_array_test: SkipByDesign # CSP policy disallows injected JS code
+js/static_interop_test/jsify_dartify_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
 js/static_interop_test/jsobject_type_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
 js/static_interop_test/native_error_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
 js/static_interop_test/typed_data_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code