Make RegexCompiler-generated code more JIT friendly (#35321)
authorStephen Toub <stoub@microsoft.com>
Sat, 25 Apr 2020 14:12:10 +0000 (10:12 -0400)
committerGitHub <noreply@github.com>
Sat, 25 Apr 2020 14:12:10 +0000 (10:12 -0400)
* Make RegexCompiler-generated code more JIT friendly

- Prefer using stloc/ldloc over using dup, especially across branches.
- Use call instead of callvirt where applicable.
- Use shorter form of some instructions

* Remove the rest of the Dups

src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs

index 685a951..ecd8c0b 100644 (file)
@@ -294,9 +294,6 @@ namespace System.Text.RegularExpressions
         /// <summary>A macro for _ilg.Emit(OpCodes.Ldc_I8).</summary>
         protected void LdcI8(long i) => _ilg!.Emit(OpCodes.Ldc_I8, i);
 
-        /// <summary>A macro for _ilg.Emit(OpCodes.Dup).</summary>
-        private void Dup() => _ilg!.Emit(OpCodes.Dup);
-
         /// <summary>A macro for _ilg.Emit(OpCodes.Ret).</summary>
         protected void Ret() => _ilg!.Emit(OpCodes.Ret);
 
@@ -348,10 +345,12 @@ namespace System.Text.RegularExpressions
         /// <summary>A macro for _ilg.Emit(OpCodes.Shr).</summary>
         private void Shr() => _ilg!.Emit(OpCodes.Shr);
 
-        /// <summary>A macro for _ilg.Emit(OpCodes.Ldloc_S).</summary>
-        private void Ldloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloc_S, lt);
+        /// <summary>A macro for _ilg.Emit(OpCodes.Ldloc).</summary>
+        /// <remarks>ILGenerator will switch to the optimal form based on the local's index.</remarks>
+        private void Ldloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloc, lt);
 
         /// <summary>A macro for _ilg.Emit(OpCodes.Ldloca).</summary>
+        /// <remarks>ILGenerator will switch to the optimal form based on the local's index.</remarks>
         private void Ldloca(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloca, lt);
 
         /// <summary>A macro for _ilg.Emit(OpCodes.Ldind_U2).</summary>
@@ -366,8 +365,9 @@ namespace System.Text.RegularExpressions
         /// <summary>A macro for _ilg.Emit(OpCodes.Unaligned).</summary>
         private void Unaligned(byte alignment) => _ilg!.Emit(OpCodes.Unaligned, alignment);
 
-        /// <summary>A macro for _ilg.Emit(OpCodes.Stloc_S).</summary>
-        private void Stloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Stloc_S, lt);
+        /// <summary>A macro for _ilg.Emit(OpCodes.Stloc).</summary>
+        /// <remarks>ILGenerator will switch to the optimal form based on the local's index.</remarks>
+        private void Stloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Stloc, lt);
 
         /// <summary>A macro for _ilg.Emit(OpCodes.Ldarg_0).</summary>
         protected void Ldthis() => _ilg!.Emit(OpCodes.Ldarg_0);
@@ -457,6 +457,9 @@ namespace System.Text.RegularExpressions
         /// <summary>A macro for _ilg.Emit(OpCodes.Bge_S) (short jump).</summary>
         private void Bge(Label l) => _ilg!.Emit(OpCodes.Bge_S, l);
 
+        /// <summary>A macro for _ilg.Emit(OpCodes.Bge_Un_S) (short jump).</summary>
+        private void BgeUn(Label l) => _ilg!.Emit(OpCodes.Bge_Un_S, l);
+
         /// <summary>A macro for _ilg.Emit(OpCodes.Bgt_S) (short jump).</summary>
         private void Bgt(Label l) => _ilg!.Emit(OpCodes.Bgt_S, l);
 
@@ -541,7 +544,7 @@ namespace System.Text.RegularExpressions
         {
             Ldloc(_runtextLocal!);
             Ldloc(_runtextposLocal!);
-            Callvirt(s_stringGetCharsMethod);
+            Call(s_stringGetCharsMethod);
         }
 
         /// <summary>Loads the char to the right of the current position and advances the current position.</summary>
@@ -549,7 +552,7 @@ namespace System.Text.RegularExpressions
         {
             Ldloc(_runtextLocal!);
             Ldloc(_runtextposLocal!);
-            Callvirt(s_stringGetCharsMethod);
+            Call(s_stringGetCharsMethod);
             Ldloc(_runtextposLocal!);
             Ldc(1);
             Add();
@@ -563,19 +566,19 @@ namespace System.Text.RegularExpressions
             Ldloc(_runtextposLocal!);
             Ldc(1);
             Sub();
-            Callvirt(s_stringGetCharsMethod);
+            Call(s_stringGetCharsMethod);
         }
 
         /// <summary>Loads the char to the left of the current position and advances (leftward).</summary>
         private void Leftcharnext()
         {
-            Ldloc(_runtextLocal!);
             Ldloc(_runtextposLocal!);
             Ldc(1);
             Sub();
-            Dup();
             Stloc(_runtextposLocal!);
-            Callvirt(s_stringGetCharsMethod);
+            Ldloc(_runtextLocal!);
+            Ldloc(_runtextposLocal!);
+            Call(s_stringGetCharsMethod);
         }
 
         /// <summary>Creates a backtrack note and pushes the switch index it on the tracking stack.</summary>
@@ -631,12 +634,12 @@ namespace System.Text.RegularExpressions
         /// <summary>Prologue to code that will push an element on the tracking stack.</summary>
         private void ReadyPushTrack()
         {
-            Ldloc(_runtrackLocal!);
             Ldloc(_runtrackposLocal!);
             Ldc(1);
             Sub();
-            Dup();
             Stloc(_runtrackposLocal!);
+            Ldloc(_runtrackLocal!);
+            Ldloc(_runtrackposLocal!);
         }
 
         /// <summary>Pops an element off the tracking stack (leave it on the operand stack).</summary>
@@ -645,10 +648,13 @@ namespace System.Text.RegularExpressions
             Ldloc(_runtrackLocal!);
             Ldloc(_runtrackposLocal!);
             LdelemI4();
+            using RentedLocalBuilder tmp = RentInt32Local();
+            Stloc(tmp);
             Ldloc(_runtrackposLocal!);
             Ldc(1);
             Add();
             Stloc(_runtrackposLocal!);
+            Ldloc(tmp);
         }
 
         /// <summary>Retrieves the top entry on the tracking stack without popping.</summary>
@@ -682,12 +688,12 @@ namespace System.Text.RegularExpressions
         /// <summary>Prologue to code that will push an element on the grouping stack.</summary>
         private void ReadyPushStack()
         {
-            Ldloc(_runstackLocal!);
             Ldloc(_runstackposLocal!);
             Ldc(1);
             Sub();
-            Dup();
             Stloc(_runstackposLocal!);
+            Ldloc(_runstackLocal!);
+            Ldloc(_runstackposLocal!);
         }
 
         /// <summary>Retrieves the top entry on the stack without popping.</summary>
@@ -701,13 +707,16 @@ namespace System.Text.RegularExpressions
         /// <summary>Pops an element off the grouping stack (leave it on the operand stack).</summary>
         private void PopStack()
         {
+            using RentedLocalBuilder elementLocal = RentInt32Local();
             Ldloc(_runstackLocal!);
             Ldloc(_runstackposLocal!);
             LdelemI4();
+            Stloc(elementLocal);
             Ldloc(_runstackposLocal!);
             Ldc(1);
             Add();
             Stloc(_runstackposLocal!);
+            Ldloc(elementLocal);
         }
 
         /// <summary>Pops 1 element off the grouping stack and discards it.</summary>
@@ -927,7 +936,7 @@ namespace System.Text.RegularExpressions
             Bge(afterDoubleStack);
             Mvlocfld(_runstackposLocal!, s_runstackposField);
             Ldthis();
-            Callvirt(s_doubleStackMethod);
+            Call(s_doubleStackMethod);
             Mvfldloc(s_runstackposField, _runstackposLocal!);
             Mvfldloc(s_runstackField, _runstackLocal!);
             MarkLabel(afterDoubleStack);
@@ -944,7 +953,7 @@ namespace System.Text.RegularExpressions
             Bge(afterDoubleTrack);
             Mvlocfld(_runtrackposLocal!, s_runtrackposField);
             Ldthis();
-            Callvirt(s_doubleTrackMethod);
+            Call(s_doubleTrackMethod);
             Mvfldloc(s_runtrackposField, _runtrackposLocal!);
             Mvfldloc(s_runtrackField, _runtrackLocal!);
             MarkLabel(afterDoubleTrack);
@@ -1161,7 +1170,7 @@ namespace System.Text.RegularExpressions
                                 Beq(l2);
                                 Ldthisfld(s_runtextField);
                                 Ldloc(_runtextposLocal);
-                                Callvirt(s_stringGetCharsMethod);
+                                Call(s_stringGetCharsMethod);
                                 Ldc('\n');
                                 Beq(l2);
                                 MarkLabel(l1);
@@ -1209,40 +1218,44 @@ namespace System.Text.RegularExpressions
                             // if (runtextpos > runtextbeg...
                             Ldloc(_runtextposLocal!);
                             Ldthisfld(s_runtextbegField);
-                            BleFar(atBeginningOfLine);
+                            Ble(atBeginningOfLine);
 
                             // ... && runtext[runtextpos - 1] != '\n') { ... }
                             Ldthisfld(s_runtextField);
                             Ldloc(_runtextposLocal);
                             Ldc(1);
                             Sub();
-                            Callvirt(s_stringGetCharsMethod);
+                            Call(s_stringGetCharsMethod);
                             Ldc('\n');
-                            BeqFar(atBeginningOfLine);
+                            Beq(atBeginningOfLine);
 
                             // int tmp = runtext.IndexOf('\n', runtextpos);
                             Ldthisfld(s_runtextField);
                             Ldc('\n');
                             Ldloc(_runtextposLocal);
                             Call(s_stringIndexOfCharInt);
-                            Dup();
-
-                            // if (tmp == -1)
-                            // {
-                            //     runtextpos = runtextend;
-                            //     return false;
-                            // }
-                            Label foundNextLine = DefineLabel();
-                            Ldc(-1);
-                            BneFar(foundNextLine);
-                            Pop();
-                            BrFar(returnFalse);
+                            using (RentedLocalBuilder newlinePos = RentInt32Local())
+                            {
+                                Stloc(newlinePos);
+
+                                // if (newlinePos == -1)
+                                // {
+                                //     runtextpos = runtextend;
+                                //     return false;
+                                // }
+                                Label foundNextLine = DefineLabel();
+                                Ldloc(newlinePos);
+                                Ldc(-1);
+                                Bne(foundNextLine);
+                                BrFar(returnFalse);
 
-                            // runtextpos = tmp + 1;
-                            MarkLabel(foundNextLine);
-                            Ldc(1);
-                            Add();
-                            Stloc(_runtextposLocal);
+                                // runtextpos = newlinePos + 1;
+                                MarkLabel(foundNextLine);
+                                Ldloc(newlinePos);
+                                Ldc(1);
+                                Add();
+                                Stloc(_runtextposLocal);
+                            }
 
                             MarkLabel(atBeginningOfLine);
                         }
@@ -1326,12 +1339,12 @@ namespace System.Text.RegularExpressions
                 {
                     CallToLower();
                 }
-                Dup();
 
                 Label lPartialMatch = DefineLabel();
                 using (RentedLocalBuilder chLocal = RentInt32Local())
                 {
                     Stloc(chLocal);
+                    Ldloc(chLocal);
                     Ldc(chLast);
 
                     BeqFar(lPartialMatch);
@@ -1341,8 +1354,8 @@ namespace System.Text.RegularExpressions
                     Ldloc(chLocal);
                     Ldc(_boyerMoorePrefix.LowASCII);
                     Sub();
-                    Dup();
                     Stloc(chLocal);
+                    Ldloc(chLocal);
                     Ldc(_boyerMoorePrefix.HighASCII - _boyerMoorePrefix.LowASCII);
                     BgtUn(lDefaultAdvance);
 
@@ -1355,9 +1368,9 @@ namespace System.Text.RegularExpressions
                         Debug.Assert(_boyerMoorePrefix.Pattern.Length <= char.MaxValue, "RegexBoyerMoore should have limited the size allowed.");
                         string negativeLookup = string.Create(negativeRange, (thisRef: this, beforefirst), (span, state) =>
                         {
-                        // Store the offsets into the string.  RightToLeft has negative offsets, so to support it with chars (unsigned), we negate
-                        // the values to be stored in the string, and then at run time after looking up the offset in the string, negate it again.
-                        for (int i = 0; i < span.Length; i++)
+                            // Store the offsets into the string.  RightToLeft has negative offsets, so to support it with chars (unsigned), we negate
+                            // the values to be stored in the string, and then at run time after looking up the offset in the string, negate it again.
+                            for (int i = 0; i < span.Length; i++)
                             {
                                 int offset = state.thisRef._boyerMoorePrefix!.NegativeASCII[i + state.thisRef._boyerMoorePrefix.LowASCII];
                                 if (offset == state.beforefirst)
@@ -1377,7 +1390,7 @@ namespace System.Text.RegularExpressions
                         // goto Advance;
                         Ldstr(negativeLookup);
                         Ldloc(chLocal);
-                        Callvirt(s_stringGetCharsMethod);
+                        Call(s_stringGetCharsMethod);
                         if (_code.RightToLeft)
                         {
                             Neg();
@@ -1415,9 +1428,9 @@ namespace System.Text.RegularExpressions
                         Ldloc(testLocal);
                         Ldc(1);
                         Sub(_code.RightToLeft);
-                        Dup();
                         Stloc(testLocal);
-                        Callvirt(s_stringGetCharsMethod);
+                        Ldloc(testLocal);
+                        Call(s_stringGetCharsMethod);
                         if (_boyerMoorePrefix.CaseInsensitive && ParticipatesInCaseConversion(_boyerMoorePrefix.Pattern[charindex]))
                         {
                             CallToLower();
@@ -1502,7 +1515,7 @@ namespace System.Text.RegularExpressions
                 if (!RegexCharClass.IsSingleton(_leadingCharClasses[0].CharClass))
                 {
                     EmitMatchCharacterClass(_leadingCharClasses[0].CharClass, _leadingCharClasses[0].CaseInsensitive);
-                    BrtrueFar(l2);
+                    Brtrue(l2);
                 }
                 else
                 {
@@ -1524,7 +1537,7 @@ namespace System.Text.RegularExpressions
                 }
 
                 Ldc(0);
-                BrFar(l3);
+                Br(l3);
 
                 MarkLabel(l2);
 
@@ -1644,17 +1657,31 @@ namespace System.Text.RegularExpressions
                             break;
                     }
 
-                    // i = tmp; // or i += tmp if there's a loop
-                    // if (tmp < 0) goto returnFalse;
-                    Dup();
                     if (needLoop)
                     {
+                        // i += tmp;
+                        // if (tmp < 0) goto returnFalse;
+                        using (RentedLocalBuilder tmp = RentInt32Local())
+                        {
+                            Stloc(tmp);
+                            Ldloc(iLocal);
+                            Ldloc(tmp);
+                            Add();
+                            Stloc(iLocal);
+                            Ldloc(tmp);
+                            Ldc(0);
+                            BltFar(returnFalse);
+                        }
+                    }
+                    else
+                    {
+                        // i = tmp;
+                        // if (i < 0) goto returnFalse;
+                        Stloc(iLocal);
                         Ldloc(iLocal);
-                        Add();
+                        Ldc(0);
+                        BltFar(returnFalse);
                     }
-                    Stloc(iLocal);
-                    Ldc(0);
-                    BltFar(returnFalse);
 
                     // if (i >= textSpan.Length - (_leadingCharClasses.Length - 1)) goto returnFalse;
                     if (_leadingCharClasses.Length > 1)
@@ -1780,11 +1807,11 @@ namespace System.Text.RegularExpressions
             Mvfldloc(s_runtextField, runtextLocal);
             Mvfldloc(s_runtextendField, runtextendLocal);
 
-            // int runtextpos;
-            // int originalruntextpos = runtextpos = this.runtextpos;
+            // int runtextpos = this.runtextpos;
+            // int originalruntextpos = this.runtextpos;
             Ldthisfld(s_runtextposField);
-            Dup();
             Stloc(runtextposLocal);
+            Ldloc(runtextposLocal);
             Stloc(originalruntextposLocal);
 
             // The implementation tries to use const indexes into the span wherever possible, which we can do
@@ -1818,7 +1845,7 @@ namespace System.Text.RegularExpressions
             Ldc(0);
             Ldloc(originalruntextposLocal);
             Ldloc(runtextposLocal);
-            Callvirt(s_captureMethod);
+            Call(s_captureMethod);
 
             // If the graph contained captures, undo any remaining to handle failed matches.
             if ((node.Options & HasCapturesFlag) != 0)
@@ -1834,10 +1861,10 @@ namespace System.Text.RegularExpressions
                 Br(condition);
                 MarkLabel(body);
                 Ldthis();
-                Callvirt(s_uncaptureMethod);
+                Call(s_uncaptureMethod);
                 MarkLabel(condition);
                 Ldthis();
-                Callvirt(s_crawlposMethod);
+                Call(s_crawlposMethod);
                 Brtrue(body);
 
                 // Done:
@@ -2138,7 +2165,7 @@ namespace System.Text.RegularExpressions
                 {
                     startingCrawlpos = RentInt32Local();
                     Ldthis();
-                    Callvirt(s_crawlposMethod);
+                    Call(s_crawlposMethod);
                     Stloc(startingCrawlpos);
                 }
 
@@ -2245,7 +2272,7 @@ namespace System.Text.RegularExpressions
                 Ldc(capnum);
                 Ldloc(startingRunTextPos);
                 Ldloc(runtextposLocal);
-                Callvirt(s_captureMethod);
+                Call(s_captureMethod);
             }
 
             // Emits code to unwind the capture stack until the crawl position specified in the provided local.
@@ -2259,10 +2286,10 @@ namespace System.Text.RegularExpressions
                 Br(condition);
                 MarkLabel(body);
                 Ldthis();
-                Callvirt(s_uncaptureMethod);
+                Call(s_uncaptureMethod);
                 MarkLabel(condition);
                 Ldthis();
-                Callvirt(s_crawlposMethod);
+                Call(s_crawlposMethod);
                 Ldloc(startingCrawlpos);
                 Bne(body);
             }
@@ -2488,23 +2515,23 @@ namespace System.Text.RegularExpressions
                 switch (node.Type)
                 {
                     case RegexNode.Boundary:
-                        Callvirt(s_isBoundaryMethod);
+                        Call(s_isBoundaryMethod);
                         BrfalseFar(doneLabel);
                         break;
 
                     case RegexNode.NonBoundary:
-                        Callvirt(s_isBoundaryMethod);
+                        Call(s_isBoundaryMethod);
                         BrtrueFar(doneLabel);
                         break;
 
                     case RegexNode.ECMABoundary:
-                        Callvirt(s_isECMABoundaryMethod);
+                        Call(s_isECMABoundaryMethod);
                         BrfalseFar(doneLabel);
                         break;
 
                     default:
                         Debug.Assert(node.Type == RegexNode.NonECMABoundary);
-                        Callvirt(s_isECMABoundaryMethod);
+                        Call(s_isECMABoundaryMethod);
                         BrtrueFar(doneLabel);
                         break;
                 }
@@ -2556,7 +2583,7 @@ namespace System.Text.RegularExpressions
                             Ldloc(runtextposLocal);
                             Ldc(1);
                             Sub();
-                            Callvirt(s_stringGetCharsMethod);
+                            Call(s_stringGetCharsMethod);
                             Ldc('\n');
                             BneFar(doneLabel);
                             MarkLabel(success);
@@ -2588,7 +2615,7 @@ namespace System.Text.RegularExpressions
                             Ldc(textSpanPos);
                             Ldloca(textSpanLocal);
                             Call(s_spanGetLengthMethod);
-                            BgeUnFar(success);
+                            BgeUn(success);
                             Ldloca(textSpanLocal);
                             Ldc(textSpanPos);
                             Call(s_spanGetItemMethod);
@@ -3334,7 +3361,7 @@ namespace System.Text.RegularExpressions
             if (_hasTimeout)
             {
                 Ldthis();
-                Callvirt(s_checkTimeoutMethod);
+                Call(s_checkTimeoutMethod);
             }
 
             // Now generate the IL for the RegEx code saved in _regexopcode.
@@ -3364,7 +3391,7 @@ namespace System.Text.RegularExpressions
                     //:     break Backward;
                     Ldthis();
                     Ldc(Operand(0));
-                    Callvirt(s_isMatchedMethod);
+                    Call(s_isMatchedMethod);
                     BrfalseFar(_backtrack);
                     break;
 
@@ -3413,8 +3440,8 @@ namespace System.Text.RegularExpressions
                     //: Textto(Stacked(0));
                     ReadyPushTrack();
                     PopStack();
-                    Dup();
                     Stloc(_runtextposLocal!);
+                    Ldloc(_runtextposLocal!);
                     DoPush();
 
                     Track();
@@ -3448,7 +3475,7 @@ namespace System.Text.RegularExpressions
                     {
                         Ldthis();
                         Ldc(Operand(1));
-                        Callvirt(s_isMatchedMethod);
+                        Call(s_isMatchedMethod);
                         BrfalseFar(_backtrack);
                     }
 
@@ -3464,7 +3491,7 @@ namespace System.Text.RegularExpressions
                             Ldc(Operand(1));
                             Ldloc(stackedLocal);
                             Ldloc(_runtextposLocal!);
-                            Callvirt(s_transferCaptureMethod);
+                            Call(s_transferCaptureMethod);
                         }
                         else
                         {
@@ -3472,7 +3499,7 @@ namespace System.Text.RegularExpressions
                             Ldc(Operand(0));
                             Ldloc(stackedLocal);
                             Ldloc(_runtextposLocal!);
-                            Callvirt(s_captureMethod);
+                            Call(s_captureMethod);
                         }
 
                         PushTrack(stackedLocal);
@@ -3493,11 +3520,11 @@ namespace System.Text.RegularExpressions
                     PopTrack();
                     DoPush();
                     Ldthis();
-                    Callvirt(s_uncaptureMethod);
+                    Call(s_uncaptureMethod);
                     if (Operand(0) != -1 && Operand(1) != -1)
                     {
                         Ldthis();
-                        Callvirt(s_uncaptureMethod);
+                        Call(s_uncaptureMethod);
                     }
                     Back();
                     break;
@@ -3521,11 +3548,11 @@ namespace System.Text.RegularExpressions
                         Label l1 = DefineLabel();
 
                         PopStack();
-                        Dup();
                         using (RentedLocalBuilder mark = RentInt32Local())
                         {
                             Stloc(mark);                        // Stacked(0) -> temp
                             PushTrack(mark);
+                            Ldloc(mark);
                         }
                         Ldloc(_runtextposLocal!);
                         Beq(l1);                                // mark == textpos -> branch
@@ -3590,8 +3617,7 @@ namespace System.Text.RegularExpressions
                         using (RentedLocalBuilder mark = RentInt32Local())
                         {
                             PopStack();
-                            Dup();
-                            Stloc(mark!);                      // Stacked(0) -> temp
+                            Stloc(mark);                      // Stacked(0) -> temp
 
                             // if (oldMarkPos != -1)
                             Label l2 = DefineLabel();
@@ -3609,6 +3635,7 @@ namespace System.Text.RegularExpressions
                             // if (Textpos() != mark)
                             Label l1 = DefineLabel();
                             Ldloc(_runtextposLocal!);
+                            Ldloc(mark);
                             Beq(l1);                            // mark == textpos -> branch
                             PushTrack(_runtextposLocal!);
                             Track();
@@ -3704,11 +3731,11 @@ namespace System.Text.RegularExpressions
                             PopStack();
                             Stloc(count);                           // count -> temp
                             PopStack();
-                            Dup();
                             using (RentedLocalBuilder mark = RentInt32Local())
                             {
                                 Stloc(mark);                        // mark -> temp2
                                 PushTrack(mark);
+                                Ldloc(mark);
                             }
 
                             Label l1 = DefineLabel();
@@ -3761,8 +3788,8 @@ namespace System.Text.RegularExpressions
                             PopStack();
                             Ldc(1);
                             Sub();
-                            Dup();
-                            Stloc(count!);
+                            Stloc(count);
+                            Ldloc(count);
                             Ldc(0);
                             Blt(l1);
 
@@ -3878,8 +3905,8 @@ namespace System.Text.RegularExpressions
                             PopTrack();
                             Stloc(_runtextposLocal!);
                             PopTrack();
-                            Dup();
                             Stloc(cLocal);
+                            Ldloc(cLocal);
                             Ldc(Operand(1));
                             Bge(l1);                                // Tracked(1) >= Operand(1) -> l1
 
@@ -3930,7 +3957,7 @@ namespace System.Text.RegularExpressions
                     DoPush();
                     ReadyPushStack();
                     Ldthis();
-                    Callvirt(s_crawlposMethod);
+                    Call(s_crawlposMethod);
                     DoPush();
                     TrackUnique(Stackpop2);
                     break;
@@ -3951,27 +3978,27 @@ namespace System.Text.RegularExpressions
                         Label l1 = DefineLabel();
                         Label l2 = DefineLabel();
 
-                        PopStack();
-                        Ldthisfld(s_runtrackField);
-                        Ldlen();
-                        PopStack();
-                        Sub();
-                        Stloc(_runtrackposLocal!);
-                        Dup();
-                        Ldthis();
-                        Callvirt(s_crawlposMethod);
-                        Beq(l2);
+                        using (RentedLocalBuilder stackedLocal = RentInt32Local())
+                        {
+                            PopStack();
+                            Stloc(stackedLocal);
+                            Ldthisfld(s_runtrackField);
+                            Ldlen();
+                            PopStack();
+                            Sub();
+                            Stloc(_runtrackposLocal!);
 
-                        MarkLabel(l1);
-                        Ldthis();
-                        Callvirt(s_uncaptureMethod);
-                        Dup();
-                        Ldthis();
-                        Callvirt(s_crawlposMethod);
-                        Bne(l1);
+                            MarkLabel(l1);
+                            Ldthis();
+                            Call(s_crawlposMethod);
+                            Ldloc(stackedLocal);
+                            Beq(l2);
+                            Ldthis();
+                            Call(s_uncaptureMethod);
+                            Br(l1);
+                        }
 
                         MarkLabel(l2);
-                        Pop();
                         Back();
                         break;
                     }
@@ -4003,23 +4030,22 @@ namespace System.Text.RegularExpressions
                         Label l1 = DefineLabel();
                         Label l2 = DefineLabel();
 
-                        PopTrack();
-
-                        Dup();
-                        Ldthis();
-                        Callvirt(s_crawlposMethod);
-                        Beq(l2);
+                        using (RentedLocalBuilder trackedLocal = RentInt32Local())
+                        {
+                            PopTrack();
+                            Stloc(trackedLocal);
 
-                        MarkLabel(l1);
-                        Ldthis();
-                        Callvirt(s_uncaptureMethod);
-                        Dup();
-                        Ldthis();
-                        Callvirt(s_crawlposMethod);
-                        Bne(l1);
+                            MarkLabel(l1);
+                            Ldthis();
+                            Call(s_crawlposMethod);
+                            Ldloc(trackedLocal);
+                            Beq(l2);
+                            Ldthis();
+                            Call(s_uncaptureMethod);
+                            Br(l1);
+                        }
 
                         MarkLabel(l2);
-                        Pop();
                         Back();
                         break;
                     }
@@ -4060,7 +4086,7 @@ namespace System.Text.RegularExpressions
                     Ldloc(_runtextposLocal!);
                     Ldloc(_runtextbegLocal!);
                     Ldloc(_runtextendLocal!);
-                    Callvirt(s_isBoundaryMethod);
+                    Call(s_isBoundaryMethod);
                     if (Code() == RegexCode.Boundary)
                     {
                         BrfalseFar(_backtrack);
@@ -4079,7 +4105,7 @@ namespace System.Text.RegularExpressions
                     Ldloc(_runtextposLocal!);
                     Ldloc(_runtextbegLocal!);
                     Ldloc(_runtextendLocal!);
-                    Callvirt(s_isECMABoundaryMethod);
+                    Call(s_isECMABoundaryMethod);
                     if (Code() == RegexCode.ECMABoundary)
                     {
                         BrfalseFar(_backtrack);
@@ -4213,7 +4239,7 @@ namespace System.Text.RegularExpressions
                                 Ldc(i);
                                 Add();
                             }
-                            Callvirt(s_stringGetCharsMethod);
+                            Call(s_stringGetCharsMethod);
                             if (IsCaseInsensitive() && ParticipatesInCaseConversion(str[i]))
                             {
                                 CallToLower();
@@ -4256,7 +4282,7 @@ namespace System.Text.RegularExpressions
                             Ldloc(_runtextposLocal!);
                             Ldc(str.Length - i);
                             Sub();
-                            Callvirt(s_stringGetCharsMethod);
+                            Call(s_stringGetCharsMethod);
                             if (IsCaseInsensitive() && ParticipatesInCaseConversion(str[i]))
                             {
                                 CallToLower();
@@ -4296,7 +4322,7 @@ namespace System.Text.RegularExpressions
 
                         Ldthis();
                         Ldc(Operand(0));
-                        Callvirt(s_isMatchedMethod);
+                        Call(s_isMatchedMethod);
                         if ((_options & RegexOptions.ECMAScript) != 0)
                         {
                             Brfalse(AdvanceLabel());
@@ -4308,9 +4334,9 @@ namespace System.Text.RegularExpressions
 
                         Ldthis();
                         Ldc(Operand(0));
-                        Callvirt(s_matchLengthMethod);
-                        Dup();
+                        Call(s_matchLengthMethod);
                         Stloc(lenLocal);
+                        Ldloc(lenLocal);
                         if (!IsRightToLeft())
                         {
                             Ldloc(_runtextendLocal!);
@@ -4326,7 +4352,7 @@ namespace System.Text.RegularExpressions
 
                         Ldthis();
                         Ldc(Operand(0));
-                        Callvirt(s_matchIndexMethod);
+                        Call(s_matchIndexMethod);
                         if (!IsRightToLeft())
                         {
                             Ldloc(lenLocal);
@@ -4350,11 +4376,11 @@ namespace System.Text.RegularExpressions
                         {
                             Ldc(1);
                             Sub();
-                            Dup();
                             Stloc(lenLocal);
+                            Ldloc(lenLocal);
                         }
                         Sub(IsRightToLeft());
-                        Callvirt(s_stringGetCharsMethod);
+                        Call(s_stringGetCharsMethod);
                         if (IsCaseInsensitive())
                         {
                             CallToLower();
@@ -4365,13 +4391,13 @@ namespace System.Text.RegularExpressions
                         Ldloc(lenLocal);
                         if (!IsRightToLeft())
                         {
-                            Dup();
+                            Ldloc(lenLocal);
                             Ldc(1);
                             Sub();
                             Stloc(lenLocal);
                         }
                         Sub(IsRightToLeft());
-                        Callvirt(s_stringGetCharsMethod);
+                        Call(s_stringGetCharsMethod);
                         if (IsCaseInsensitive())
                         {
                             CallToLower();
@@ -4438,19 +4464,19 @@ namespace System.Text.RegularExpressions
                         {
                             Ldc(1);
                             Sub();
-                            Dup();
                             Stloc(lenLocal);
+                            Ldloc(lenLocal);
                             Add();
                         }
                         else
                         {
-                            Dup();
+                            Ldloc(lenLocal);
                             Ldc(1);
                             Sub();
                             Stloc(lenLocal);
                             Sub();
                         }
-                        Callvirt(s_stringGetCharsMethod);
+                        Call(s_stringGetCharsMethod);
 
                         if (Code() == RegexCode.Setrep)
                         {
@@ -4548,17 +4574,17 @@ namespace System.Text.RegularExpressions
                             Ldloc(_runtextbegLocal!);
                         }
                         Sub();
+                        Stloc(lenLocal);
                         if (c != int.MaxValue)
                         {
                             Label l4 = DefineLabel();
-                            Dup();
+                            Ldloc(lenLocal);
                             Ldc(c);
                             Blt(l4);
-                            Pop();
                             Ldc(c);
+                            Stloc(lenLocal);
                             MarkLabel(l4);
                         }
-                        Stloc(lenLocal);
 
                         Label loopEnd = DefineLabel();
                         string? set = Code() == RegexCode.Setloop || Code() == RegexCode.Setloopatomic ? _strings![Operand(0)] : null;
@@ -4708,8 +4734,8 @@ namespace System.Text.RegularExpressions
                             Ldloc(iLocal);
                             Ldc(1);
                             Sub();
-                            Dup();
                             Stloc(iLocal);
+                            Ldloc(iLocal);
                             Ldc(0);
                             if (Code() == RegexCode.Setloop || Code() == RegexCode.Setloopatomic)
                             {
@@ -4867,20 +4893,20 @@ namespace System.Text.RegularExpressions
                             Ldloc(_runtextbegLocal!);
                         }
                         Sub();
-                        if (c != int.MaxValue)
-                        {
-                            Label l4 = DefineLabel();
-                            Dup();
-                            Ldc(c);
-                            Blt(l4);
-                            Pop();
-                            Ldc(c);
-                            MarkLabel(l4);
-                        }
-                        Dup();
                         using (RentedLocalBuilder cLocal = RentInt32Local())
                         {
                             Stloc(cLocal);
+                            if (c != int.MaxValue)
+                            {
+                                Label l4 = DefineLabel();
+                                Ldloc(cLocal);
+                                Ldc(c);
+                                Blt(l4);
+                                Ldc(c);
+                                Stloc(cLocal);
+                                MarkLabel(l4);
+                            }
+                            Ldloc(cLocal);
                             Ldc(0);
                             Ble(AdvanceLabel());
                             ReadyPushTrack();
@@ -5115,6 +5141,8 @@ namespace System.Text.RegularExpressions
                 }
             }
 
+            using RentedLocalBuilder resultLocal = RentInt32Local();
+
             // Analyze the character set more to determine what code to generate.
             RegexCharClass.CharClassAnalysisResults analysis = RegexCharClass.Analyze(charClass);
 
@@ -5128,6 +5156,7 @@ namespace System.Text.RegularExpressions
                 }
                 Ldstr(charClass);
                 Call(s_charInClassMethod);
+                Stloc(resultLocal);
             }
 
             Label doneLabel = DefineLabel();
@@ -5151,7 +5180,9 @@ namespace System.Text.RegularExpressions
                     Br(doneLabel);
                     MarkLabel(comparisonLabel);
                     Ldc(0);
+                    Stloc(resultLocal);
                     MarkLabel(doneLabel);
+                    Ldloc(resultLocal);
                     return;
                 }
 
@@ -5169,7 +5200,9 @@ namespace System.Text.RegularExpressions
                     Br(doneLabel);
                     MarkLabel(comparisonLabel);
                     Ldc(1);
+                    Stloc(resultLocal);
                     MarkLabel(doneLabel);
+                    Ldloc(resultLocal);
                     return;
                 }
             }
@@ -5226,6 +5259,7 @@ namespace System.Text.RegularExpressions
             And();
             Ldc(0);
             CgtUn();
+            Stloc(resultLocal);
             Br(doneLabel);
             MarkLabel(comparisonLabel);
 
@@ -5235,6 +5269,7 @@ namespace System.Text.RegularExpressions
                 // character class were [A-Za-z0-9], so since the ch is now known to be >= 128, we
                 // can just fail the comparison.
                 Ldc(0);
+                Stloc(resultLocal);
             }
             else if (analysis.AllNonAsciiContained)
             {
@@ -5242,6 +5277,7 @@ namespace System.Text.RegularExpressions
                 // class were [^\r\n], so since we just determined the ch to be >= 128, we can just
                 // give back success.
                 Ldc(1);
+                Stloc(resultLocal);
             }
             else
             {
@@ -5251,6 +5287,7 @@ namespace System.Text.RegularExpressions
                 EmitCharInClass();
             }
             MarkLabel(doneLabel);
+            Ldloc(resultLocal);
         }
 
         /// <summary>Emits a timeout check.</summary>
@@ -5276,7 +5313,7 @@ namespace System.Text.RegularExpressions
             RemUn();
             Brtrue(label);
             Ldthis();
-            Callvirt(s_checkTimeoutMethod);
+            Call(s_checkTimeoutMethod);
             MarkLabel(label);
         }
 
@@ -5289,7 +5326,7 @@ namespace System.Text.RegularExpressions
             Mvlocfld(_runtrackposLocal!, s_runtrackposField);
             Mvlocfld(_runstackposLocal!, s_runstackposField);
             Ldthis();
-            Callvirt(s_dumpStateM);
+            Call(s_dumpStateM);
 
             var sb = new StringBuilder();
             if (_backpos > 0)