[Wasm] cache chars for WasmJs String (KT-73240)
diff --git a/libraries/stdlib/wasm/js/builtins/kotlin/String.kt b/libraries/stdlib/wasm/js/builtins/kotlin/String.kt
index e5ea09c..6b93a40 100644
--- a/libraries/stdlib/wasm/js/builtins/kotlin/String.kt
+++ b/libraries/stdlib/wasm/js/builtins/kotlin/String.kt
@@ -16,6 +16,8 @@
 
 public actual class String internal @WasmPrimitiveConstructor constructor(
     public val internalStr: JsString,
+    @kotlin.internal.IntrinsicConstEvaluation
+    private var _chars: WasmCharArray?
 ) : Comparable<String>, CharSequence {
     public actual companion object {}
 
@@ -31,7 +33,7 @@
     @kotlin.internal.IntrinsicConstEvaluation
     public actual operator fun plus(other: Any?): String {
         val right = other.toString()
-        return String(jsConcat(this.internalStr, right.internalStr))
+        return String(jsConcat(this.internalStr, right.internalStr), null)
     }
 
     @kotlin.internal.IntrinsicConstEvaluation
@@ -40,17 +42,19 @@
         return jsCharCodeAt(this.internalStr, index).reinterpretAsChar()
     }
 
-    @kotlin.internal.IntrinsicConstEvaluation
     internal val chars: WasmCharArray
         get() {
-            val copy = WasmCharArray(length)
-            jsIntoCharCodeArray(internalStr, copy, 0)
-            return copy
+            if (_chars == null) {
+                val copy = WasmCharArray(length)
+                jsIntoCharCodeArray(internalStr, copy, 0)
+                _chars = copy
+            }
+            return _chars!!
         }
 
     public actual override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
         checkStringBounds(startIndex, endIndex, length)
-        return String(jsSubstring(this.internalStr, startIndex, endIndex))
+        return String(jsSubstring(this.internalStr, startIndex, endIndex), null)
     }
 
     private fun checkStringBounds(startIndex: Int, endIndex: Int, length: Int) {
@@ -108,6 +112,6 @@
 
 @Suppress("NOTHING_TO_INLINE")
 internal actual inline fun WasmCharArray.createString(): String =
-    String(jsFromCharCodeArray(this, 0, this.len()))
+    String(jsFromCharCodeArray(this, 0, this.len()), this)
 
 internal actual fun String.getChars() = this.chars
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/js/internal/ExternalWrapper.kt b/libraries/stdlib/wasm/js/internal/ExternalWrapper.kt
index 914c150..a6acf6b 100644
--- a/libraries/stdlib/wasm/js/internal/ExternalWrapper.kt
+++ b/libraries/stdlib/wasm/js/internal/ExternalWrapper.kt
@@ -190,7 +190,7 @@
 
 internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
     val jsStr: JsString = x.unsafeCast()
-    return String(jsStr)
+    return String(jsStr, null)
 }