[dart2wasm] Replace js_util implementations with UnsupportedError

Bug: #61550
Change-Id: I6a6a6964fb0fe0f67c5963889b4399c565cab3c7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450949
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 370e994..35e1412 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -164,6 +164,15 @@
 [#54573]: https://github.com/dart-lang/sdk/issues/54573
 [#61567]: https://github.com/dart-lang/sdk/issues/61567
 
+#### `dart:js_util`
+
+- dart2wasm no longer supports `dart:js_util` and will throw an
+  `UnsupportedError` if any API from this library is invoked. This also applies
+  to `package:js/js_util.dart`. `package:js/js.dart` continues to be supported. 
+  See [#61550][] for more details.
+
+[#61550]: https://github.com/dart-lang/sdk/issues/61550
+
 ## 3.9.0
 
 **Released on:** 2025-08-13
diff --git a/sdk/lib/_internal/wasm/lib/js_util_patch.dart b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
index 0fcc7b5..dccc530 100644
--- a/sdk/lib/_internal/wasm/lib/js_util_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
@@ -5,256 +5,99 @@
 library dart.js_util;
 
 import "dart:_internal";
-import "dart:_js_helper";
-import "dart:_js_types";
-import "dart:js_interop"
-    show
-        JSAnyUtilityExtension,
-        FunctionToJSExportedDartFunction,
-        dartify,
-        JSAny,
-        NullRejectionException;
-import "dart:_wasm";
-import "dart:async" show Completer, FutureOr;
-import "dart:collection";
-import "dart:typed_data";
+
+Never _unsupported() =>
+    throw UnsupportedError('js_util is not supported by dart2wasm');
 
 @patch
-dynamic jsify(Object? object) {
-  final convertedObjects = HashMap<Object?, Object?>.identity();
-  Object? convert(Object? o) {
-    if (convertedObjects.containsKey(o)) {
-      return convertedObjects[o];
-    }
-
-    // TODO(srujzs): We do these checks again in `jsifyRaw`. We should refactor
-    // this code so we don't have to, but we have to be careful about the
-    // `Iterable` check below.
-    if (o == null ||
-        o is num ||
-        o is bool ||
-        o is JSValue ||
-        o is String ||
-        (o is TypedData &&
-            (o is Int8List ||
-                o is Uint8List ||
-                o is Uint8ClampedList ||
-                o is Int16List ||
-                o is Uint16List ||
-                o is Int32List ||
-                o is Uint32List ||
-                o is Float32List ||
-                o is Float64List ||
-                o is ByteData)) ||
-        o is ByteBuffer) {
-      return JSValue(jsifyRaw(o));
-    }
-
-    if (o is Map<Object?, Object?>) {
-      final convertedMap = newObject<JSValue>();
-      convertedObjects[o] = convertedMap;
-      for (final key in o.keys) {
-        final convertedKey = convert(key) as JSValue?;
-        setPropertyRaw(
-          convertedMap.toExternRef,
-          convertedKey.toExternRef,
-          (convert(o[key]) as JSValue?).toExternRef,
-        );
-      }
-      return convertedMap;
-    } else if (o is Iterable<Object?>) {
-      final convertedIterable = _newArray();
-      convertedObjects[o] = convertedIterable;
-      for (final item in o) {
-        callMethod(convertedIterable, 'push', [convert(item)]);
-      }
-      return convertedIterable;
-    } else {
-      // None of the objects left will require recursive conversions.
-      return JSValue(jsifyRaw(o));
-    }
-  }
-
-  return convert(object);
-}
+dynamic jsify(Object? object) => _unsupported();
 
 @patch
-Object get globalThis => JSValue(globalThisRaw());
+Object get globalThis => _unsupported();
 
 @patch
-T newObject<T>() => JSValue(newObjectRaw()) as T;
-
-JSValue _newArray() => JSValue(newArrayRaw());
+T newObject<T>() => _unsupported();
 
 @patch
-bool hasProperty(Object o, Object name) =>
-    hasPropertyRaw(jsifyRaw(o), jsifyRaw(name));
+bool hasProperty(Object o, Object name) => _unsupported();
 
 @patch
-T getProperty<T>(Object o, Object name) =>
-    dartifyRaw(getPropertyRaw(jsifyRaw(o), jsifyRaw(name))) as T;
+T getProperty<T>(Object o, Object name) => _unsupported();
 
 @patch
-T setProperty<T>(Object o, Object name, T? value) =>
-    dartifyRaw(setPropertyRaw(jsifyRaw(o), jsifyRaw(name), jsifyRaw(value)))
-        as T;
+T setProperty<T>(Object o, Object name, T? value) => _unsupported();
 
 @patch
-T callMethod<T>(Object o, Object method, List<Object?> args) =>
-    dartifyRaw(
-          callMethodVarArgsRaw(jsifyRaw(o), jsifyRaw(method), jsifyRaw(args)),
-        )
-        as T;
+T callMethod<T>(Object o, Object method, List<Object?> args) => _unsupported();
 
 @patch
-bool instanceof(Object? o, Object type) =>
-    JS<bool>("(o, t) => o instanceof t", jsifyRaw(o), jsifyRaw(type));
+bool instanceof(Object? o, Object type) => _unsupported();
 
 @patch
-T callConstructor<T>(Object o, List<Object?>? args) =>
-    dartifyRaw(callConstructorVarArgsRaw(jsifyRaw(o), jsifyRaw(args))) as T;
+T callConstructor<T>(Object o, List<Object?>? args) => _unsupported();
 
 @patch
-T add<T>(Object? first, Object? second) => throw 'unimplemented';
+T add<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-T subtract<T>(Object? first, Object? second) => throw 'unimplemented';
+T subtract<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-T multiply<T>(Object? first, Object? second) => throw 'unimplemented';
+T multiply<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-T divide<T>(Object? first, Object? second) => throw 'unimplemented';
+T divide<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-T exponentiate<T>(Object? first, Object? second) => throw 'unimplemented';
+T exponentiate<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-T modulo<T>(Object? first, Object? second) => throw 'unimplemented';
+T modulo<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool equal<T>(Object? first, Object? second) => throw 'unimplemented';
+bool equal<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool strictEqual<T>(Object? first, Object? second) => throw 'unimplemented';
+bool strictEqual<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool notEqual<T>(Object? first, Object? second) => throw 'unimplemented';
+bool notEqual<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool strictNotEqual<T>(Object? first, Object? second) => throw 'unimplemented';
+bool strictNotEqual<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool greaterThan<T>(Object? first, Object? second) => throw 'unimplemented';
+bool greaterThan<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool greaterThanOrEqual<T>(Object? first, Object? second) =>
-    throw 'unimplemented';
+bool greaterThanOrEqual<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool lessThan<T>(Object? first, Object? second) => throw 'unimplemented';
+bool lessThan<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool lessThanOrEqual<T>(Object? first, Object? second) => throw 'unimplemented';
+bool lessThanOrEqual<T>(Object? first, Object? second) => _unsupported();
 
 @patch
-bool typeofEquals<T>(Object? o, String type) =>
-    JS<bool>('(o, t) => typeof o === t', jsifyRaw(o), jsifyRaw(type));
-
-typedef _PromiseSuccessFunc = void Function(Object? value);
-typedef _PromiseFailureFunc = void Function(Object? error);
+bool typeofEquals<T>(Object? o, String type) => _unsupported();
 
 @patch
-Future<T> promiseToFuture<T>(Object jsPromise) {
-  Completer<T> completer = Completer<T>();
-
-  final success = ((JSAny? jsValue) {
-    final r = dartifyRaw(jsValue.toExternRef);
-    return completer.complete(r as FutureOr<T>?);
-  }).toJS;
-  final error = (JSAny? jsError, bool isUndefined) {
-    // `jsError` is null when the original error is either JS `null` or JS
-    // `undefined`.
-    final e = dartifyRaw(jsError.toExternRef);
-    if (e == null) {
-      completer.completeError(NullRejectionException(isUndefined));
-      return;
-    }
-    completer.completeError(e);
-  }.toJS;
-  promiseThenWithIsUndefined(
-    jsifyRaw(jsPromise),
-    success.toExternRef,
-    error.toExternRef,
-  );
-  return completer.future;
-}
+Future<T> promiseToFuture<T>(Object jsPromise) => _unsupported();
 
 @patch
-Object? objectGetPrototypeOf(Object? object) => throw 'unimplemented';
+Object? objectGetPrototypeOf(Object? object) => _unsupported();
 
 @patch
-Object? get objectPrototype => throw 'unimplemented';
+Object? get objectPrototype => _unsupported();
 
 @patch
-List<Object?> objectKeys(Object? o) =>
-    toDartList(JS<WasmExternRef?>('o => Object.keys(o)', jsifyRaw(o)));
+List<Object?> objectKeys(Object? o) => _unsupported();
 
 @patch
-Object? dartify(Object? object) {
-  final convertedObjects = HashMap<Object?, Object?>.identity();
-  Object? convert(Object? o) {
-    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].
-    if (o is List<Object?>) {
-      final converted = <Object?>[];
-      for (final item in o) {
-        converted.add(convert(item));
-      }
-      return converted;
-    }
-    if (o is! JSValue) return o;
-    WasmExternRef? ref = o.toExternRef;
-    final refType = externRefType(ref);
-    // TODO(srujzs): Either handle Date and Promise, or remove them completely
-    // from the conversion (preferred) across all backends.
-    if (refType == ExternRefType.unknown && isJSSimpleObject(ref)) {
-      final dartMap = <Object?, Object?>{};
-      convertedObjects[o] = dartMap;
-      // Keys will be a list of Dart [String]s.
-      final keys = objectKeys(o);
-      for (int i = 0; i < keys.length; i++) {
-        final key = keys[i];
-        if (key != null) {
-          dartMap[key] = convert(
-            JSValue.box(getPropertyRaw(ref, jsifyRaw(key))),
-          );
-        }
-      }
-      return dartMap;
-    }
-    if (refType == ExternRefType.array) {
-      final dartList = <Object?>[];
-      convertedObjects[o] = dartList;
-      final length = getProperty<double>(o, 'length').toInt();
-      for (int i = 0; i < length; i++) {
-        dartList.add(convert(JSValue.box(objectReadIndex(ref, i))));
-      }
-      return dartList;
-    }
-    return dartifyRaw(ref, refType);
-  }
-
-  return convert(object);
-}
-
-/// This will be lowered to a a call to `_wrapDartCallback`.
-@patch
-F allowInterop<F extends Function>(F f) => throw UnimplementedError();
+Object? dartify(Object? object) => _unsupported();
 
 @patch
-Function allowInteropCaptureThis(Function f) => throw UnimplementedError();
+F allowInterop<F extends Function>(F f) => _unsupported();
+
+@patch
+Function allowInteropCaptureThis(Function f) => _unsupported();