[dart2wasm] Use the same Dart object when to{Upper,Lower}Case returns the argument

This fixes `identical` checks when the input doesn't need case mapping.

This change was originally made in [1], but I'm trying to split it into
smaller CLs as it currently has a lot of conflicts with the main branch.

[1]: https://dart-review.googlesource.com/c/sdk/+/316628

Change-Id: I88da52a3a73c9d587acefe2b14fd39edaf01c966
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332200
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
diff --git a/sdk/lib/_internal/wasm/lib/js_string.dart b/sdk/lib/_internal/wasm/lib/js_string.dart
index 59834a8..e500265 100644
--- a/sdk/lib/_internal/wasm/lib/js_string.dart
+++ b/sdk/lib/_internal/wasm/lib/js_string.dart
@@ -319,14 +319,20 @@
 
   @override
   String toLowerCase() {
-    return JSStringImpl(
-        js.JS<WasmExternRef?>('s => s.toLowerCase()', toExternRef));
+    final thisRef = toExternRef;
+    final lowerCaseRef = js.JS<WasmExternRef?>('s => s.toLowerCase()', thisRef);
+    return _jsIdentical(thisRef, lowerCaseRef)
+        ? this
+        : JSStringImpl(lowerCaseRef);
   }
 
   @override
   String toUpperCase() {
-    return JSStringImpl(
-        js.JS<WasmExternRef?>('s => s.toUpperCase()', toExternRef));
+    final thisRef = toExternRef;
+    final upperCaseRef = js.JS<WasmExternRef?>('s => s.toUpperCase()', thisRef);
+    return _jsIdentical(thisRef, upperCaseRef)
+        ? this
+        : JSStringImpl(upperCaseRef);
   }
 
   // Characters with Whitespace property (Unicode 6.3).
@@ -679,3 +685,6 @@
 @pragma("wasm:export", "\$jsStringFromJSStringImpl")
 WasmExternRef? _jsStringFromJSStringImpl(JSStringImpl string) =>
     string.toExternRef;
+
+bool _jsIdentical(WasmExternRef? ref1, WasmExternRef? ref2) =>
+    js.JS<bool>('Object.is', ref1, ref2);