[Regex] Replace a child set list with an array on the hot path

JointSet descendants excessively iterate over their child sets.
With lists being used, such iteration has a significant overhead related
to iterator allocation and various additional condition checks.
diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/AtomicJointSet.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/AtomicJointSet.kt
index a3fcbaa..2c2e068 100644
--- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/AtomicJointSet.kt
+++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/AtomicJointSet.kt
@@ -31,8 +31,8 @@
     override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
         val start = matchResult.getConsumed(groupIndex)
         matchResult.setConsumed(groupIndex, startIndex)
-        children.forEach {
-            val shift = it.matches(startIndex, testString, matchResult)
+        forEachChildrenIndexed { _, child ->
+            val shift = child.matches(startIndex, testString, matchResult)
             if (shift >= 0) {
                 // AtomicFset always returns true, but saves the index to run this next.match() from;
                 return next.matches((fSet as AtomicFSet).index, testString, matchResult)
diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/JointSet.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/JointSet.kt
index fce62bf..f02daed 100644
--- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/JointSet.kt
+++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/JointSet.kt
@@ -30,7 +30,7 @@
  */
 open internal class JointSet(children: List<AbstractSet>, fSet: FSet) : AbstractSet() {
 
-    protected var children: MutableList<AbstractSet> = mutableListOf<AbstractSet>().apply { addAll(children) }
+    private var children = children.toTypedArray()
 
     var fSet: FSet = fSet
         protected set
@@ -79,8 +79,18 @@
             assert(newFSet == fSet)
         }
 
-        @OptIn(ExperimentalNativeApi::class)
-        children.replaceAll { child -> if (!child.secondPassVisited) child.processSecondPass() else child }
+        children.forEachIndexed { index, child ->
+            if (!child.secondPassVisited) {
+                children[index] = child.processSecondPass()
+            }
+        }
+
         return super.processSecondPassInternal()
     }
+
+    protected inline fun forEachChildrenIndexed(action: (index: Int, child: AbstractSet) -> Unit) {
+        for (index in children.indices) {
+            action(index, children[index])
+        }
+    }
 }
diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookAheadSets.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookAheadSets.kt
index 13b5ea2..045f5dc 100644
--- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookAheadSets.kt
+++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookAheadSets.kt
@@ -29,8 +29,8 @@
 
     /** Returns startIndex+shift, the next position to match */
     override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
-        children.forEach {
-            val shift = it.matches(startIndex, testString, matchResult)
+        forEachChildrenIndexed { _, child ->
+            val shift = child.matches(startIndex, testString, matchResult)
             if (shift >= 0) {
                 // PosLookaheadFset always returns true, position remains the same next.match() from;
                 return next.matches(startIndex, testString, matchResult)
@@ -50,8 +50,8 @@
 
     /** Returns startIndex+shift, the next position to match */
     override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
-        children.forEach {
-            if (it.matches(startIndex, testString, matchResult) >= 0) {
+        forEachChildrenIndexed { _, child ->
+            if (child.matches(startIndex, testString, matchResult) >= 0) {
                 return -1
             }
         }
diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookBehindSets.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookBehindSets.kt
index d577ea7..ffb2cc4 100644
--- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookBehindSets.kt
+++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/LookBehindSets.kt
@@ -48,8 +48,13 @@
         children[it].computeMatchLengthInChars(fSet)
     }
 
-    protected fun matchPrefix(childIndex: Int, startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
-        val child = children[childIndex]
+    protected fun matchPrefix(
+        childIndex: Int,
+        child: AbstractSet,
+        startIndex: Int,
+        testString: CharSequence,
+        matchResult: MatchResultImpl
+    ): Int {
         val prefixLength = prefixLengths[childIndex]
         return when {
             // the prefix length is unknown, so lets fallback to a generic matching
@@ -69,8 +74,8 @@
     /** Returns startIndex+shift, the next position to match */
     override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
         matchResult.setConsumed(groupIndex, startIndex)
-        for (idx in children.indices) {
-            if (matchPrefix(idx, startIndex, testString, matchResult) >= 0) {
+        forEachChildrenIndexed { idx, child ->
+            if (matchPrefix(idx, child, startIndex, testString, matchResult) >= 0) {
                 matchResult.setConsumed(groupIndex, -1)
                 return next.matches(startIndex, testString, matchResult)
             }
@@ -90,8 +95,8 @@
     /** Returns startIndex+shift, the next position to match */
     override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
         matchResult.setConsumed(groupIndex, startIndex)
-        for (idx in children.indices) {
-            if (matchPrefix(idx, startIndex,testString, matchResult) >= 0) {
+        forEachChildrenIndexed { idx, child ->
+            if (matchPrefix(idx, child, startIndex, testString, matchResult) >= 0) {
                 return -1
             }
         }
diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/NonCapturingJointSet.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/NonCapturingJointSet.kt
index 07f7ec4..0b31ecc 100644
--- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/NonCapturingJointSet.kt
+++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/sets/NonCapturingJointSet.kt
@@ -34,8 +34,8 @@
         val start = matchResult.getConsumed(groupIndex)
         matchResult.setConsumed(groupIndex, startIndex)
 
-        children.forEach {
-            val shift = it.matches(startIndex, testString, matchResult)
+        forEachChildrenIndexed { _, child ->
+            val shift = child.matches(startIndex, testString, matchResult)
             if (shift >= 0) {
                 return shift
             }