1 //------------------------------------------------------------------------------
2 // <copyright file="RegexCompiler.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 // The RegexCompiler class is internal to the Regex package.
8 // It translates a block of RegexCode to MSIL, and creates a
9 // subclass of the RegexRunner type.
12 #if !SILVERLIGHT && !FULL_AOT_RUNTIME
14 namespace System.Text.RegularExpressions {
16 using System.Collections;
17 using System.Collections.Generic;
18 using System.Threading;
19 using System.Reflection;
20 using System.Reflection.Emit;
21 using System.Security;
22 using System.Security.Policy;
23 using System.Security.Permissions;
24 using System.Diagnostics;
25 using System.Diagnostics.CodeAnalysis;
26 using System.Globalization;
27 using System.Runtime.Versioning;
32 * Because dynamic modules are expensive and not thread-safe, we create
33 * one dynamic module per-thread, and cache as much information about it
36 * While we're at it, we just create one RegexCompiler per thread
37 * as well, and have RegexCompiler inherit from RegexDynamicModule.
39 internal abstract class RegexCompiler {
40 // fields that never change (making them saves about 6% overall running time)
42 internal static FieldInfo _textbegF;
43 internal static FieldInfo _textendF;
44 internal static FieldInfo _textstartF;
45 internal static FieldInfo _textposF;
46 internal static FieldInfo _textF;
47 internal static FieldInfo _trackposF;
48 internal static FieldInfo _trackF;
49 internal static FieldInfo _stackposF;
50 internal static FieldInfo _stackF;
51 internal static FieldInfo _trackcountF;
55 internal static MethodInfo _ensurestorageM;
56 internal static MethodInfo _captureM;
57 internal static MethodInfo _transferM;
58 internal static MethodInfo _uncaptureM;
59 internal static MethodInfo _ismatchedM;
60 internal static MethodInfo _matchlengthM;
61 internal static MethodInfo _matchindexM;
62 internal static MethodInfo _isboundaryM;
63 internal static MethodInfo _isECMABoundaryM;
64 internal static MethodInfo _chartolowerM;
65 internal static MethodInfo _getcharM;
66 internal static MethodInfo _crawlposM;
67 internal static MethodInfo _charInSetM;
68 internal static MethodInfo _getCurrentCulture;
69 internal static MethodInfo _getInvariantCulture;
70 internal static MethodInfo _checkTimeoutM;
72 internal static MethodInfo _dumpstateM;
75 internal ILGenerator _ilg;
77 // tokens representing local variables
78 internal LocalBuilder _textstartV;
79 internal LocalBuilder _textbegV;
80 internal LocalBuilder _textendV;
81 internal LocalBuilder _textposV;
82 internal LocalBuilder _textV;
83 internal LocalBuilder _trackposV;
84 internal LocalBuilder _trackV;
85 internal LocalBuilder _stackposV;
86 internal LocalBuilder _stackV;
87 internal LocalBuilder _tempV;
88 internal LocalBuilder _temp2V;
89 internal LocalBuilder _temp3V;
92 internal RegexCode _code; // the RegexCode object (used for debugging only)
93 internal int[] _codes; // the RegexCodes being translated
94 internal String[] _strings; // the stringtable associated with the RegexCodes
95 internal RegexPrefix _fcPrefix; // the possible first chars computed by RegexFCD
96 internal RegexBoyerMoore _bmPrefix; // a prefix as a boyer-moore machine
97 internal int _anchors; // the set of anchors
99 internal Label[] _labels; // a label for every operation in _codes
100 internal BacktrackNote[] _notes; // a list of the backtracking states to be generated
101 internal int _notecount; // true count of _notes (allocation grows exponentially)
102 internal int _trackcount; // count of backtracking states (used to reduce allocations)
104 internal Label _backtrack; // label for backtracking
107 internal int _regexopcode; // the current opcode being processed
108 internal int _codepos; // the current code being translated
109 internal int _backpos; // the current backtrack-note being translated
111 internal RegexOptions _options; // options
113 // special code fragments
114 internal int[] _uniquenote; // _notes indices for code that should be emitted <= once
115 internal int[] _goto; // indices for forward-jumps-through-switch (for allocations)
117 // indices for unique code fragments
118 internal const int stackpop = 0; // pop one
119 internal const int stackpop2 = 1; // pop two
120 internal const int stackpop3 = 2; // pop three
121 internal const int capback = 3; // uncapture
122 internal const int capback2 = 4; // uncapture 2
123 internal const int branchmarkback2 = 5; // back2 part of branchmark
124 internal const int lazybranchmarkback2 = 6; // back2 part of lazybranchmark
125 internal const int branchcountback2 = 7; // back2 part of branchcount
126 internal const int lazybranchcountback2 = 8; // back2 part of lazybranchcount
127 internal const int forejumpback = 9; // back part of forejump
128 internal const int uniquecount = 10;
130 static RegexCompiler() {
131 // <SECREVIEW> Regex only generates string manipulation, so this is ok.
135 new ReflectionPermission(PermissionState.Unrestricted).Assert();
139 _textbegF = RegexRunnerField("runtextbeg");
140 _textendF = RegexRunnerField("runtextend");
141 _textstartF = RegexRunnerField("runtextstart");
142 _textposF = RegexRunnerField("runtextpos");
143 _textF = RegexRunnerField("runtext");
144 _trackposF = RegexRunnerField("runtrackpos");
145 _trackF = RegexRunnerField("runtrack");
146 _stackposF = RegexRunnerField("runstackpos");
147 _stackF = RegexRunnerField("runstack");
148 _trackcountF = RegexRunnerField("runtrackcount");
151 _ensurestorageM = RegexRunnerMethod("EnsureStorage");
152 _captureM = RegexRunnerMethod("Capture");
153 _transferM = RegexRunnerMethod("TransferCapture");
154 _uncaptureM = RegexRunnerMethod("Uncapture");
155 _ismatchedM = RegexRunnerMethod("IsMatched");
156 _matchlengthM = RegexRunnerMethod("MatchLength");
157 _matchindexM = RegexRunnerMethod("MatchIndex");
158 _isboundaryM = RegexRunnerMethod("IsBoundary");
159 _charInSetM = RegexRunnerMethod("CharInClass");
160 _isECMABoundaryM= RegexRunnerMethod("IsECMABoundary");
161 _crawlposM = RegexRunnerMethod("Crawlpos");
162 _checkTimeoutM = RegexRunnerMethod("CheckTimeout");
164 _chartolowerM = typeof(Char).GetMethod("ToLower", new Type[] {typeof(Char), typeof(CultureInfo)});
165 _getcharM = typeof(String).GetMethod("get_Chars", new Type[] {typeof(int)});
166 _getCurrentCulture = typeof(CultureInfo).GetMethod("get_CurrentCulture");
167 _getInvariantCulture = typeof(CultureInfo).GetMethod("get_InvariantCulture");
171 _dumpstateM = RegexRunnerMethod("DumpState");
176 CodeAccessPermission.RevertAssert();
181 private static FieldInfo RegexRunnerField(String fieldname) {
182 return typeof(RegexRunner).GetField(fieldname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
185 private static MethodInfo RegexRunnerMethod(String methname) {
186 return typeof(RegexRunner).GetMethod(methname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
191 * Entry point to dynamically compile a regular expression. The expression is compiled to
192 * an in-memory assembly.
194 internal static RegexRunnerFactory Compile(RegexCode code, RegexOptions options) {
195 RegexLWCGCompiler c = new RegexLWCGCompiler();
196 RegexRunnerFactory factory;
198 // <SECREVIEW> Regex only generates string manipulation, so this is ok.
201 new ReflectionPermission(PermissionState.Unrestricted).Assert();
204 factory = c.FactoryInstanceFromCode(code, options);
208 CodeAccessPermission.RevertAssert();
215 * Compile regular expressions into an assembly on disk.
217 [ResourceExposure(ResourceScope.Machine)]
218 [ResourceConsumption(ResourceScope.Machine)]
219 [SuppressMessage("Microsoft.Security","CA2106:SecureAsserts", Justification="[....]: SECREVIEW : Regex only generates string manipulation, so this is OK")]
220 internal static void CompileToAssembly(RegexCompilationInfo[] regexes, AssemblyName an, CustomAttributeBuilder[] attribs, String resourceFile) {
221 RegexTypeCompiler c = new RegexTypeCompiler(an, attribs, resourceFile);
223 for (int i=0; i<regexes.Length; i++) {
224 if (regexes[i] == null) {
225 throw new ArgumentNullException("regexes", SR.GetString(SR.ArgumentNull_ArrayWithNullElements));
227 String pattern = regexes[i].Pattern;
228 RegexOptions options = regexes[i].Options;
230 if (regexes[i].Namespace.Length == 0)
231 fullname = regexes[i].Name;
233 fullname = regexes[i].Namespace + "." + regexes[i].Name;
235 TimeSpan mTimeout = regexes[i].MatchTimeout;
237 RegexTree tree = RegexParser.Parse(pattern, options);
238 RegexCode code = RegexWriter.Write(tree);
243 new ReflectionPermission(PermissionState.Unrestricted).Assert();
246 factory = c.FactoryTypeFromCode(code, options, fullname);
247 c.GenerateRegexType(pattern, options, fullname, regexes[i].IsPublic, code, tree, factory, mTimeout);
251 CodeAccessPermission.RevertAssert();
261 * Keeps track of an operation that needs to be referenced in the backtrack-jump
262 * switch table, and that needs backtracking code to be emitted (if flags != 0)
264 internal sealed class BacktrackNote {
265 internal BacktrackNote(int flags, Label label, int codepos) {
271 internal int _codepos;
273 internal Label _label;
277 * Adds a backtrack note to the list of them, and returns the index of the new
278 * note (which is also the index for the jump used by the switch table)
280 internal int AddBacktrackNote(int flags, Label l, int codepos) {
281 if (_notes == null || _notecount >= _notes.Length) {
282 BacktrackNote[] newnotes = new BacktrackNote[_notes == null ? 16 : _notes.Length * 2];
284 System.Array.Copy(_notes, 0, newnotes, 0, _notecount);
288 _notes[_notecount] = new BacktrackNote(flags, l, codepos);
294 * Adds a backtrack note for the current operation; creates a new label for
295 * where the code will be, and returns the switch index.
297 internal int AddTrack() {
298 return AddTrack(RegexCode.Back);
302 * Adds a backtrack note for the current operation; creates a new label for
303 * where the code will be, and returns the switch index.
305 internal int AddTrack(int flags) {
306 return AddBacktrackNote(flags, DefineLabel(), _codepos);
310 * Adds a switchtable entry for the specified position (for the forward
311 * logic; does not cause backtracking logic to be generated)
313 internal int AddGoto(int destpos) {
314 if (_goto[destpos] == -1)
315 _goto[destpos] = AddBacktrackNote(0, _labels[destpos], destpos);
317 return _goto[destpos];
321 * Adds a note for backtracking code that only needs to be generated once;
322 * if it's already marked to be generated, returns the switch index
323 * for the unique piece of code.
325 internal int AddUniqueTrack(int i) {
326 return AddUniqueTrack(i, RegexCode.Back);
330 * Adds a note for backtracking code that only needs to be generated once;
331 * if it's already marked to be generated, returns the switch index
332 * for the unique piece of code.
334 internal int AddUniqueTrack(int i, int flags) {
335 if (_uniquenote[i] == -1)
336 _uniquenote[i] = AddTrack(flags);
338 return _uniquenote[i];
342 * A macro for _ilg.DefineLabel
344 internal Label DefineLabel() {
345 return _ilg.DefineLabel();
349 * A macro for _ilg.MarkLabel
351 internal void MarkLabel(Label l) {
356 * Returns the ith operand of the current operation
358 internal int Operand(int i) {
359 return _codes[_codepos + i + 1];
363 * True if the current operation is marked for the leftward direction
365 internal bool IsRtl() {
366 return(_regexopcode & RegexCode.Rtl) != 0;
370 * True if the current operation is marked for case insensitive operation
372 internal bool IsCi() {
373 return(_regexopcode & RegexCode.Ci) != 0;
378 * True if we need to do the backtrack logic for the current operation
380 internal bool IsBack() {
381 return(_regexopcode & RegexCode.Back) != 0;
385 * True if we need to do the second-backtrack logic for the current operation
387 internal bool IsBack2() {
388 return(_regexopcode & RegexCode.Back2) != 0;
393 * Returns the raw regex opcode (masking out Back and Rtl)
395 internal int Code() {
396 return _regexopcode & RegexCode.Mask;
399 internal void Ldstr(string str) {
400 _ilg.Emit(OpCodes.Ldstr, str);
404 * A macro for the various forms of Ldc
406 internal void Ldc(int i) {
407 if (i <= 127 && i >= -128)
408 _ilg.Emit(OpCodes.Ldc_I4_S, (byte)i);
410 _ilg.Emit(OpCodes.Ldc_I4, i);
413 internal void LdcI8(long i) {
414 if (i <= Int32.MaxValue && i >= Int32.MinValue) {
416 _ilg.Emit(OpCodes.Conv_I8);
418 _ilg.Emit(OpCodes.Ldc_I8, i);
423 * A macro for _ilg.Emit(OpCodes.Dup)
425 internal void Dup() {
426 _ilg.Emit(OpCodes.Dup);
430 * A macro for _ilg.Emit(OpCodes.Ret)
432 internal void Ret() {
433 _ilg.Emit(OpCodes.Ret);
437 * A macro for _ilg.Emit(OpCodes.Pop)
439 internal void Pop() {
440 _ilg.Emit(OpCodes.Pop);
444 * A macro for _ilg.Emit(OpCodes.Add)
446 internal void Add() {
447 _ilg.Emit(OpCodes.Add);
451 * A macro for _ilg.Emit(OpCodes.Add); a true flag can turn it into a Sub
453 internal void Add(bool negate) {
455 _ilg.Emit(OpCodes.Sub);
457 _ilg.Emit(OpCodes.Add);
461 * A macro for _ilg.Emit(OpCodes.Sub)
463 internal void Sub() {
464 _ilg.Emit(OpCodes.Sub);
468 * A macro for _ilg.Emit(OpCodes.Sub); a true flag can turn it into a Add
470 internal void Sub(bool negate) {
472 _ilg.Emit(OpCodes.Add);
474 _ilg.Emit(OpCodes.Sub);
478 * A macro for _ilg.Emit(OpCodes.Ldloc);
480 internal void Ldloc(LocalBuilder lt) {
481 _ilg.Emit(OpCodes.Ldloc_S, lt);
485 * A macro for _ilg.Emit(OpCodes.Stloc);
487 internal void Stloc(LocalBuilder lt) {
488 _ilg.Emit(OpCodes.Stloc_S, lt);
492 * A macro for _ilg.Emit(OpCodes.Ldarg_0);
494 internal void Ldthis() {
495 _ilg.Emit(OpCodes.Ldarg_0);
499 * A macro for Ldthis(); Ldfld();
501 internal void Ldthisfld(FieldInfo ft) {
503 _ilg.Emit(OpCodes.Ldfld, ft);
507 * A macro for Ldthis(); Ldfld(); Stloc();
509 internal void Mvfldloc(FieldInfo ft, LocalBuilder lt) {
515 * A macro for Ldthis(); Ldthisfld(); Stloc();
517 internal void Mvlocfld(LocalBuilder lt, FieldInfo ft) {
524 * A macro for _ilg.Emit(OpCodes.Stfld);
526 internal void Stfld(FieldInfo ft) {
527 _ilg.Emit(OpCodes.Stfld, ft);
531 * A macro for _ilg.Emit(OpCodes.Callvirt);
533 internal void Callvirt(MethodInfo mt) {
534 _ilg.Emit(OpCodes.Callvirt, mt);
538 * A macro for _ilg.Emit(OpCodes.Call);
540 internal void Call(MethodInfo mt) {
541 _ilg.Emit(OpCodes.Call, mt);
545 * A macro for _ilg.Emit(OpCodes.Newobj);
547 internal void Newobj(ConstructorInfo ct) {
548 _ilg.Emit(OpCodes.Newobj, ct);
552 * A macro for _ilg.Emit(OpCodes.Brfalse) (long form)
554 internal void BrfalseFar(Label l) {
555 _ilg.Emit(OpCodes.Brfalse, l);
559 * A macro for _ilg.Emit(OpCodes.Brtrue) (long form)
561 internal void BrtrueFar(Label l) {
562 _ilg.Emit(OpCodes.Brtrue, l);
566 * A macro for _ilg.Emit(OpCodes.Br) (long form)
568 internal void BrFar(Label l) {
569 _ilg.Emit(OpCodes.Br, l);
573 * A macro for _ilg.Emit(OpCodes.Ble) (long form)
575 internal void BleFar(Label l) {
576 _ilg.Emit(OpCodes.Ble, l);
580 * A macro for _ilg.Emit(OpCodes.Blt) (long form)
582 internal void BltFar(Label l) {
583 _ilg.Emit(OpCodes.Blt, l);
587 * A macro for _ilg.Emit(OpCodes.Bge) (long form)
589 internal void BgeFar(Label l) {
590 _ilg.Emit(OpCodes.Bge, l);
594 * A macro for _ilg.Emit(OpCodes.Bgt) (long form)
596 internal void BgtFar(Label l) {
597 _ilg.Emit(OpCodes.Bgt, l);
601 * A macro for _ilg.Emit(OpCodes.Bne) (long form)
603 internal void BneFar(Label l) {
604 _ilg.Emit(OpCodes.Bne_Un, l);
608 * A macro for _ilg.Emit(OpCodes.Beq) (long form)
610 internal void BeqFar(Label l) {
611 _ilg.Emit(OpCodes.Beq, l);
615 * A macro for _ilg.Emit(OpCodes.Brfalse_S) (short jump)
617 internal void Brfalse(Label l) {
618 _ilg.Emit(OpCodes.Brfalse_S, l);
622 * A macro for _ilg.Emit(OpCodes.Br_S) (short jump)
624 internal void Br(Label l) {
625 _ilg.Emit(OpCodes.Br_S, l);
629 * A macro for _ilg.Emit(OpCodes.Ble_S) (short jump)
631 internal void Ble(Label l) {
632 _ilg.Emit(OpCodes.Ble_S, l);
636 * A macro for _ilg.Emit(OpCodes.Blt_S) (short jump)
638 internal void Blt(Label l) {
639 _ilg.Emit(OpCodes.Blt_S, l);
643 * A macro for _ilg.Emit(OpCodes.Bge_S) (short jump)
645 internal void Bge(Label l) {
646 _ilg.Emit(OpCodes.Bge_S, l);
650 * A macro for _ilg.Emit(OpCodes.Bgt_S) (short jump)
652 internal void Bgt(Label l) {
653 _ilg.Emit(OpCodes.Bgt_S, l);
657 * A macro for _ilg.Emit(OpCodes.Bleun_S) (short jump)
659 internal void Bgtun(Label l) {
660 _ilg.Emit(OpCodes.Bgt_Un_S, l);
664 * A macro for _ilg.Emit(OpCodes.Bne_S) (short jump)
666 internal void Bne(Label l) {
667 _ilg.Emit(OpCodes.Bne_Un_S, l);
671 * A macro for _ilg.Emit(OpCodes.Beq_S) (short jump)
673 internal void Beq(Label l) {
674 _ilg.Emit(OpCodes.Beq_S, l);
678 * A macro for the Ldlen instruction
680 internal void Ldlen() {
681 _ilg.Emit(OpCodes.Ldlen);
685 * Loads the char to the right of the current position
687 internal void Rightchar() {
694 * Loads the char to the right of the current position and advances the current position
696 internal void Rightcharnext() {
707 * Loads the char to the left of the current position
709 internal void Leftchar() {
718 * Loads the char to the left of the current position and advances (leftward)
720 internal void Leftcharnext() {
731 * Creates a backtrack note and pushes the switch index it on the tracking stack
733 internal void Track() {
740 * Pushes the current switch index on the tracking stack so the backtracking
741 * logic will be repeated again next time we backtrack here.
746 internal void Trackagain() {
753 * Saves the value of a local variable on the tracking stack
755 internal void PushTrack(LocalBuilder lt) {
762 * Creates a backtrack note for a piece of code that should only be generated once,
763 * and emits code that pushes the switch index on the backtracking stack.
765 internal void TrackUnique(int i) {
767 Ldc(AddUniqueTrack(i));
772 * Creates a second-backtrack note for a piece of code that should only be
773 * generated once, and emits code that pushes the switch index on the
774 * backtracking stack.
776 internal void TrackUnique2(int i) {
778 Ldc(AddUniqueTrack(i, RegexCode.Back2));
783 * Prologue to code that will push an element on the tracking stack
785 internal void ReadyPushTrack() {
786 _ilg.Emit(OpCodes.Ldloc_S, _trackV);
787 _ilg.Emit(OpCodes.Ldloc_S, _trackposV);
788 _ilg.Emit(OpCodes.Ldc_I4_1);
789 _ilg.Emit(OpCodes.Sub);
790 _ilg.Emit(OpCodes.Dup);
791 _ilg.Emit(OpCodes.Stloc_S, _trackposV);
795 * Pops an element off the tracking stack (leave it on the operand stack)
797 internal void PopTrack() {
798 _ilg.Emit(OpCodes.Ldloc_S, _trackV);
799 _ilg.Emit(OpCodes.Ldloc_S, _trackposV);
800 _ilg.Emit(OpCodes.Dup);
801 _ilg.Emit(OpCodes.Ldc_I4_1);
802 _ilg.Emit(OpCodes.Add);
803 _ilg.Emit(OpCodes.Stloc_S, _trackposV);
804 _ilg.Emit(OpCodes.Ldelem_I4);
808 * Retrieves the top entry on the tracking stack without popping
810 internal void TopTrack() {
811 _ilg.Emit(OpCodes.Ldloc_S, _trackV);
812 _ilg.Emit(OpCodes.Ldloc_S, _trackposV);
813 _ilg.Emit(OpCodes.Ldelem_I4);
817 * Saves the value of a local variable on the grouping stack
819 internal void PushStack(LocalBuilder lt) {
821 _ilg.Emit(OpCodes.Ldloc_S, lt);
826 * Prologue to code that will replace the ith element on the grouping stack
828 internal void ReadyReplaceStack(int i) {
829 _ilg.Emit(OpCodes.Ldloc_S, _stackV);
830 _ilg.Emit(OpCodes.Ldloc_S, _stackposV);
833 _ilg.Emit(OpCodes.Add);
838 * Prologue to code that will push an element on the grouping stack
840 internal void ReadyPushStack() {
841 _ilg.Emit(OpCodes.Ldloc_S, _stackV);
842 _ilg.Emit(OpCodes.Ldloc_S, _stackposV);
843 _ilg.Emit(OpCodes.Ldc_I4_1);
844 _ilg.Emit(OpCodes.Sub);
845 _ilg.Emit(OpCodes.Dup);
846 _ilg.Emit(OpCodes.Stloc_S, _stackposV);
850 * Retrieves the top entry on the stack without popping
852 internal void TopStack() {
853 _ilg.Emit(OpCodes.Ldloc_S, _stackV);
854 _ilg.Emit(OpCodes.Ldloc_S, _stackposV);
855 _ilg.Emit(OpCodes.Ldelem_I4);
859 * Pops an element off the grouping stack (leave it on the operand stack)
861 internal void PopStack() {
862 _ilg.Emit(OpCodes.Ldloc_S, _stackV);
863 _ilg.Emit(OpCodes.Ldloc_S, _stackposV);
864 _ilg.Emit(OpCodes.Dup);
865 _ilg.Emit(OpCodes.Ldc_I4_1);
866 _ilg.Emit(OpCodes.Add);
867 _ilg.Emit(OpCodes.Stloc_S, _stackposV);
868 _ilg.Emit(OpCodes.Ldelem_I4);
872 * Pops 1 element off the grouping stack and discards it
874 internal void PopDiscardStack() {
879 * Pops i elements off the grouping stack and discards them
881 internal void PopDiscardStack(int i) {
882 _ilg.Emit(OpCodes.Ldloc_S, _stackposV);
884 _ilg.Emit(OpCodes.Add);
885 _ilg.Emit(OpCodes.Stloc_S, _stackposV);
889 * Epilogue to code that will replace an element on a stack (use Ld* in between)
891 internal void DoReplace() {
892 _ilg.Emit(OpCodes.Stelem_I4);
896 * Epilogue to code that will push an element on a stack (use Ld* in between)
898 internal void DoPush() {
899 _ilg.Emit(OpCodes.Stelem_I4);
903 * Jump to the backtracking switch
905 internal void Back() {
906 _ilg.Emit(OpCodes.Br, _backtrack);
910 * Branch to the MSIL corresponding to the regex code at i
912 * A trick: since track and stack space is gobbled up unboundedly
913 * only as a result of branching backwards, this is where we check
914 * for sufficient space and trigger reallocations.
916 * If the "goto" is backwards, we generate code that checks
917 * available space against the amount of space that would be needed
918 * in the worst case by code that will only go forward; if there's
919 * not enough, we push the destination on the tracking stack, then
920 * we jump to the place where we invoke the allocator.
922 * Since forward gotos pose no threat, they just turn into a Br.
924 internal void Goto(int i) {
926 Label l1 = DefineLabel();
928 // When going backwards, ensure enough space.
930 Ldc(_trackcount * 4);
933 Ldc(_trackcount * 3);
947 * Returns the position of the next operation in the regex code, taking
948 * into account the different numbers of arguments taken by operations
950 internal int NextCodepos() {
951 return _codepos + RegexCode.OpcodeSize(_codes[_codepos]);
955 * The label for the next (forward) operation
957 internal Label AdvanceLabel() {
958 return _labels[NextCodepos()];
962 * Goto the next (forward) operation
964 internal void Advance() {
965 _ilg.Emit(OpCodes.Br, AdvanceLabel());
968 internal void CallToLower()
970 if ((_options & RegexOptions.CultureInvariant) != 0)
971 Call(_getInvariantCulture);
973 Call(_getCurrentCulture);
979 * Generates the first section of the MSIL. This section contains all
980 * the forward logic, and corresponds directly to the regex codes.
982 * In the absence of backtracking, this is all we would need.
984 internal void GenerateForwardSection() {
987 _labels = new Label[_codes.Length];
988 _goto = new int[_codes.Length];
992 for (codepos = 0; codepos < _codes.Length; codepos += RegexCode.OpcodeSize(_codes[codepos])) {
994 _labels[codepos] = _ilg.DefineLabel();
997 _uniquenote = new int[uniquecount];
998 for (int i = 0; i < uniquecount; i++)
1001 // emit variable initializers
1003 Mvfldloc(_textF, _textV);
1004 Mvfldloc(_textstartF, _textstartV);
1005 Mvfldloc(_textbegF, _textbegV);
1006 Mvfldloc(_textendF, _textendV);
1007 Mvfldloc(_textposF, _textposV);
1008 Mvfldloc(_trackF, _trackV);
1009 Mvfldloc(_trackposF, _trackposV);
1010 Mvfldloc(_stackF, _stackV);
1011 Mvfldloc(_stackposF, _stackposV);
1015 for (codepos = 0; codepos < _codes.Length; codepos += RegexCode.OpcodeSize(_codes[codepos])) {
1016 MarkLabel(_labels[codepos]);
1018 _regexopcode = _codes[codepos];
1024 * Generates the middle section of the MSIL. This section contains the
1025 * big switch jump that allows us to simulate a stack of addresses,
1026 * and it also contains the calls that expand the tracking and the
1027 * grouping stack when they get too full.
1029 internal void GenerateMiddleSection() {
1030 #pragma warning disable 219
1031 Label l1 = DefineLabel();
1032 #pragma warning restore 219
1037 MarkLabel(_backtrack);
1039 // first call EnsureStorage
1040 Mvlocfld(_trackposV, _trackposF);
1041 Mvlocfld(_stackposV, _stackposF);
1043 Callvirt(_ensurestorageM);
1044 Mvfldloc(_trackposF, _trackposV);
1045 Mvfldloc(_stackposF, _stackposV);
1046 Mvfldloc(_trackF, _trackV);
1047 Mvfldloc(_stackF, _stackV);
1052 table = new Label[_notecount];
1053 for (i = 0; i < _notecount; i++)
1054 table[i] = _notes[i]._label;
1056 _ilg.Emit(OpCodes.Switch, table);
1061 * Generates the last section of the MSIL. This section contains all of
1062 * the backtracking logic.
1064 internal void GenerateBacktrackSection() {
1067 for (i = 0; i < _notecount; i++) {
1068 BacktrackNote n = _notes[i];
1069 if (n._flags != 0) {
1070 _ilg.MarkLabel(n._label);
1071 _codepos = n._codepos;
1073 _regexopcode = _codes[n._codepos] | n._flags;
1080 * Generates FindFirstChar
1082 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1083 // !!!! This function must be kept synchronized with FindFirstChar in !!!!
1084 // !!!! RegexInterpreter.cs !!!!
1085 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1086 internal void GenerateFindFirstChar() {
1087 _textposV = DeclareInt();
1088 _textV = DeclareString();
1089 _tempV = DeclareInt();
1090 _temp2V = DeclareInt();
1092 if (0 != (_anchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End))) {
1093 if (!_code._rightToLeft) {
1094 if (0 != (_anchors & RegexFCD.Beginning)) {
1095 Label l1 = DefineLabel();
1096 Ldthisfld(_textposF);
1097 Ldthisfld(_textbegF);
1100 Ldthisfld(_textendF);
1107 if (0 != (_anchors & RegexFCD.Start)) {
1108 Label l1 = DefineLabel();
1109 Ldthisfld(_textposF);
1110 Ldthisfld(_textstartF);
1113 Ldthisfld(_textendF);
1120 if (0 != (_anchors & RegexFCD.EndZ)) {
1121 Label l1 = DefineLabel();
1122 Ldthisfld(_textposF);
1123 Ldthisfld(_textendF);
1128 Ldthisfld(_textendF);
1135 if (0 != (_anchors & RegexFCD.End)) {
1136 Label l1 = DefineLabel();
1137 Ldthisfld(_textposF);
1138 Ldthisfld(_textendF);
1141 Ldthisfld(_textendF);
1147 if (0 != (_anchors & RegexFCD.End)) {
1148 Label l1 = DefineLabel();
1149 Ldthisfld(_textposF);
1150 Ldthisfld(_textendF);
1153 Ldthisfld(_textbegF);
1160 if (0 != (_anchors & RegexFCD.EndZ)) {
1161 Label l1 = DefineLabel();
1162 Label l2 = DefineLabel();
1163 Ldthisfld(_textposF);
1164 Ldthisfld(_textendF);
1168 Ldthisfld(_textposF);
1169 Ldthisfld(_textendF);
1172 Ldthisfld(_textposF);
1173 Callvirt(_getcharM);
1178 Ldthisfld(_textbegF);
1185 if (0 != (_anchors & RegexFCD.Start)) {
1186 Label l1 = DefineLabel();
1187 Ldthisfld(_textposF);
1188 Ldthisfld(_textstartF);
1191 Ldthisfld(_textbegF);
1198 if (0 != (_anchors & RegexFCD.Beginning)) {
1199 Label l1 = DefineLabel();
1200 Ldthisfld(_textposF);
1201 Ldthisfld(_textbegF);
1204 Ldthisfld(_textbegF);
1216 else if (_bmPrefix != null && _bmPrefix._negativeUnicode == null) {
1217 // Compiled Boyer-Moore string matching
1221 LocalBuilder chV = _tempV;
1222 LocalBuilder testV = _tempV;
1223 LocalBuilder limitV = _temp2V;
1224 Label lDefaultAdvance = DefineLabel();
1225 Label lAdvance = DefineLabel();
1226 Label lFail = DefineLabel();
1227 Label lStart = DefineLabel();
1228 #pragma warning disable 219
1229 Label lOutOfRange = DefineLabel();
1230 #pragma warning restore 219
1231 Label lPartialMatch = DefineLabel();
1240 if (!_code._rightToLeft) {
1242 last = _bmPrefix._pattern.Length - 1;
1245 beforefirst = _bmPrefix._pattern.Length;
1249 chLast = _bmPrefix._pattern[last];
1251 Mvfldloc(_textF, _textV);
1252 if (!_code._rightToLeft)
1253 Ldthisfld(_textendF);
1255 Ldthisfld(_textbegF);
1258 Ldthisfld(_textposF);
1259 if (!_code._rightToLeft) {
1260 Ldc(_bmPrefix._pattern.Length - 1);
1264 Ldc(_bmPrefix._pattern.Length);
1270 MarkLabel(lDefaultAdvance);
1272 if (!_code._rightToLeft)
1273 Ldc(_bmPrefix._pattern.Length);
1275 Ldc(-_bmPrefix._pattern.Length);
1277 MarkLabel(lAdvance);
1287 if (!_code._rightToLeft)
1293 if (_bmPrefix._caseInsensitive)
1299 BeqFar(lPartialMatch);
1302 Ldc(_bmPrefix._lowASCII);
1306 Ldc(_bmPrefix._highASCII - _bmPrefix._lowASCII);
1307 Bgtun(lDefaultAdvance);
1309 table = new Label[_bmPrefix._highASCII - _bmPrefix._lowASCII + 1];
1311 for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++) {
1312 if (_bmPrefix._negativeASCII[i] == beforefirst)
1313 table[i - _bmPrefix._lowASCII] = lDefaultAdvance;
1315 table[i - _bmPrefix._lowASCII] = DefineLabel();
1319 _ilg.Emit(OpCodes.Switch, table);
1321 for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++) {
1322 if (_bmPrefix._negativeASCII[i] == beforefirst)
1325 MarkLabel(table[i - _bmPrefix._lowASCII]);
1327 Ldc(_bmPrefix._negativeASCII[i]);
1331 MarkLabel(lPartialMatch);
1336 for (i = _bmPrefix._pattern.Length - 2; i >= 0; i--) {
1337 Label lNext = DefineLabel();
1340 if (!_code._rightToLeft)
1343 charindex = _bmPrefix._pattern.Length - 1 - i;
1348 Sub(_code._rightToLeft);
1351 Callvirt(_getcharM);
1352 if (_bmPrefix._caseInsensitive)
1355 Ldc(_bmPrefix._pattern[charindex]);
1357 Ldc(_bmPrefix._positive[charindex]);
1366 if (_code._rightToLeft) {
1377 if (!_code._rightToLeft)
1378 Ldthisfld(_textendF);
1380 Ldthisfld(_textbegF);
1385 else if (_fcPrefix == null) {
1390 LocalBuilder cV = _temp2V;
1391 #pragma warning disable 219
1392 LocalBuilder chV = _tempV;
1393 #pragma warning restore 219
1394 Label l1 = DefineLabel();
1395 Label l2 = DefineLabel();
1396 Label l3 = DefineLabel();
1397 Label l4 = DefineLabel();
1398 Label l5 = DefineLabel();
1400 Mvfldloc(_textposF, _textposV);
1401 Mvfldloc(_textF, _textV);
1403 if (!_code._rightToLeft) {
1404 Ldthisfld(_textendF);
1409 Ldthisfld(_textbegF);
1425 if (_code._rightToLeft)
1430 if (_fcPrefix.CaseInsensitive)
1433 if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix)) {
1434 Ldstr(_fcPrefix.Prefix);
1440 Ldc(RegexCharClass.SingletonChar(_fcPrefix.Prefix));
1448 if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix))
1458 /* // CURRENTLY DISABLED
1459 // If for some reason we have a prefix we didn't use, use it now.
1461 if (_bmPrefix != null) {
1462 if (!_code._rightToLeft) {
1463 Ldthisfld(_textendF);
1468 Ldthisfld(_textbegF);
1471 Ldc(_bmPrefix._pattern.Length - 1);
1474 for (int i = 1; i < _bmPrefix._pattern.Length; i++) {
1477 if (!_code._rightToLeft) {
1485 Callvirt(_getcharM);
1486 if (!_code._rightToLeft)
1487 Ldc(_bmPrefix._pattern[i]);
1489 Ldc(_bmPrefix._pattern[_bmPrefix._pattern.Length - 1 - i]);
1497 Sub(_code._rightToLeft);
1503 Mvlocfld(_textposV, _textposF);
1514 * Generates a very simple method that sets the _trackcount field.
1516 internal void GenerateInitTrackCount() {
1519 Stfld(_trackcountF);
1524 * Declares a local int
1526 internal LocalBuilder DeclareInt() {
1527 return _ilg.DeclareLocal(typeof(int));
1531 * Declares a local int array
1533 internal LocalBuilder DeclareIntArray() {
1534 return _ilg.DeclareLocal(typeof(int[]));
1538 * Declares a local string
1540 internal LocalBuilder DeclareString() {
1541 return _ilg.DeclareLocal(typeof(string));
1545 * Generates the code for "RegexRunner.Go"
1547 internal void GenerateGo() {
1548 // declare some locals
1550 _textposV = DeclareInt();
1551 _textV = DeclareString();
1552 _trackposV = DeclareInt();
1553 _trackV = DeclareIntArray();
1554 _stackposV = DeclareInt();
1555 _stackV = DeclareIntArray();
1556 _tempV = DeclareInt();
1557 _temp2V = DeclareInt();
1558 _temp3V = DeclareInt();
1559 _textbegV = DeclareInt();
1560 _textendV = DeclareInt();
1561 _textstartV = DeclareInt();
1563 // clear some tables
1569 // globally used labels
1571 _backtrack = DefineLabel();
1575 GenerateForwardSection();
1576 GenerateMiddleSection();
1577 GenerateBacktrackSection();
1582 * Some simple debugging stuff
1584 internal static MethodInfo _debugWriteLine = typeof(Debug).GetMethod("WriteLine", new Type[] {typeof(string)});
1587 * Debug only: emit code to print out a message
1589 internal void Message(String str) {
1591 Call(_debugWriteLine);
1597 * The main translation function. It translates the logic for a single opcode at
1598 * the current position. The structure of this function exactly mirrors
1599 * the structure of the inner loop of RegexInterpreter.Go().
1601 * The C# code from RegexInterpreter.Go() that corresponds to each case is
1602 * included as a comment.
1604 * Note that since we're generating code, we can collapse many cases that are
1605 * dealt with one-at-a-time in RegexIntepreter. We can also unroll loops that
1606 * iterate over constant strings or sets.
1608 internal void GenerateOneCode() {
1610 if ((_options & RegexOptions.Debug) != 0) {
1611 Mvlocfld(_textposV, _textposF);
1612 Mvlocfld(_trackposV, _trackposF);
1613 Mvlocfld(_stackposV, _stackposF);
1615 Callvirt(_dumpstateM);
1616 StringBuilder sb = new StringBuilder();
1618 sb.AppendFormat("{0:D6} ", _backpos);
1621 sb.Append(_code.OpcodeDescription(_codepos));
1625 sb.Append(" Back2");
1626 Message(sb.ToString());
1630 // Before executing any RegEx code in the unrolled loop,
1631 // we try checking for the match timeout:
1634 Callvirt(_checkTimeoutM);
1636 // Now generate the IL for the RegEx code saved in _regexopcode.
1637 // We unroll the loop done by the RegexCompiler creating as very long method
1638 // that is longer if the pattern is longer:
1640 switch (_regexopcode) {
1641 case RegexCode.Stop:
1643 Mvlocfld(_textposV, _textposF); // update _textpos
1647 case RegexCode.Nothing:
1652 case RegexCode.Goto:
1653 //: Goto(Operand(0));
1657 case RegexCode.Testref:
1658 //: if (!_match.IsMatched(Operand(0)))
1662 Callvirt(_ismatchedM);
1663 BrfalseFar(_backtrack);
1666 case RegexCode.Lazybranch:
1667 //: Track(Textpos());
1668 PushTrack(_textposV);
1672 case RegexCode.Lazybranch | RegexCode.Back:
1674 //: Textto(Tracked(0));
1675 //: Goto(Operand(0));
1681 case RegexCode.Nullmark:
1687 TrackUnique(stackpop);
1690 case RegexCode.Setmark:
1691 //: Stack(Textpos());
1693 PushStack(_textposV);
1694 TrackUnique(stackpop);
1697 case RegexCode.Nullmark | RegexCode.Back:
1698 case RegexCode.Setmark | RegexCode.Back:
1705 case RegexCode.Getmark:
1707 //: Track(Stacked(0));
1708 //: Textto(Stacked(0));
1718 case RegexCode.Getmark | RegexCode.Back:
1720 //: Stack(Tracked(0));
1728 case RegexCode.Capturemark:
1729 //: if (!IsMatched(Operand(1)))
1732 //: if (Operand(1) != -1)
1733 //: TransferCapture(Operand(0), Operand(1), Stacked(0), Textpos());
1735 //: Capture(Operand(0), Stacked(0), Textpos());
1736 //: Track(Stacked(0));
1739 //: Capture(Operand(0), Stacked(0), Textpos());
1740 //: Track(Stacked(0));
1742 if (Operand(1) != -1) {
1745 Callvirt(_ismatchedM);
1746 BrfalseFar(_backtrack);
1752 if (Operand(1) != -1) {
1758 Callvirt(_transferM);
1765 Callvirt(_captureM);
1770 if (Operand(0) != -1 && Operand(1) != -1)
1771 TrackUnique(capback2);
1773 TrackUnique(capback);
1778 case RegexCode.Capturemark | RegexCode.Back:
1780 //: Stack(Tracked(0));
1782 //: if (Operand(0) != -1 && Operand(1) != -1)
1789 Callvirt(_uncaptureM);
1790 if (Operand(0) != -1 && Operand(1) != -1) {
1792 Callvirt(_uncaptureM);
1797 case RegexCode.Branchmark:
1800 //: if (Textpos() != Stacked(0))
1801 //: { // Nonempty match -> loop now
1802 //: Track(Stacked(0), Textpos()); // Save old mark, textpos
1803 //: Stack(Textpos()); // Make new mark
1804 //: Goto(Operand(0)); // Loop
1807 //: { // Empty match -> straight now
1808 //: Track2(Stacked(0)); // Save old mark
1809 //: Advance(1); // Straight
1811 //: continue Forward;
1813 LocalBuilder mark = _tempV;
1814 Label l1 = DefineLabel();
1818 Stloc(mark); // Stacked(0) -> temp
1821 Beq(l1); // mark == textpos -> branch
1825 PushTrack(_textposV);
1826 PushStack(_textposV);
1828 Goto(Operand(0)); // Goto(Operand(0))
1833 TrackUnique2(branchmarkback2);
1837 case RegexCode.Branchmark | RegexCode.Back:
1840 //: Textto(Tracked(1)); // Recall position
1841 //: Track2(Tracked(0)); // Save old mark
1847 // track spot 0 is already in place
1848 TrackUnique2(branchmarkback2);
1852 case RegexCode.Branchmark | RegexCode.Back2:
1854 //: Stack(Tracked(0)); // Recall old mark
1855 //: break Backward; // Backtrack
1863 case RegexCode.Lazybranchmark:
1865 //: int oldMarkPos = StackPeek();
1867 //: if (Textpos() != oldMarkPos) { // Nonempty match -> next loop
1868 //: { // Nonempty match -> next loop
1869 //: if (oldMarkPos != -1)
1870 //: Track(Stacked(0), Textpos()); // Save old mark, textpos
1872 //: TrackPush(Textpos(), Textpos());
1875 //: { // Empty match -> no loop
1876 //: Track2(Stacked(0)); // Save old mark
1879 //: continue Forward;
1881 LocalBuilder mark = _tempV;
1882 Label l1 = DefineLabel();
1883 Label l2 = DefineLabel();
1884 Label l3 = DefineLabel();
1888 Stloc(mark); // Stacked(0) -> temp
1890 // if (oldMarkPos != -1)
1893 Beq(l2); // mark == -1 -> branch
1898 PushTrack(_textposV);
1901 // if (Textpos() != mark)
1903 Beq(l1); // mark == textpos -> branch
1904 PushTrack(_textposV);
1906 Br(AdvanceLabel()); // Advance (near)
1909 ReadyPushStack(); // push the current textPos on the stack.
1910 // May be ignored by 'back2' or used by a true empty match.
1914 TrackUnique2(lazybranchmarkback2);
1919 case RegexCode.Lazybranchmark | RegexCode.Back:
1921 //: Track2(Tracked(0)); // Save old mark
1922 //: Stack(Textpos()); // Make new mark
1923 //: Textto(Tracked(1)); // Recall position
1924 //: Goto(Operand(0)); // Loop
1928 PushStack(_textposV);
1929 TrackUnique2(lazybranchmarkback2);
1933 case RegexCode.Lazybranchmark | RegexCode.Back2:
1936 //: Stack(Tracked(0)); // Recall old mark
1938 ReadyReplaceStack(0);
1944 case RegexCode.Nullcount:
1945 //: Stack(-1, Operand(0));
1953 TrackUnique(stackpop2);
1956 case RegexCode.Setcount:
1957 //: Stack(Textpos(), Operand(0));
1959 PushStack(_textposV);
1963 TrackUnique(stackpop2);
1967 case RegexCode.Nullcount | RegexCode.Back:
1968 case RegexCode.Setcount | RegexCode.Back:
1976 case RegexCode.Branchcount:
1978 //: int mark = Stacked(0);
1979 //: int count = Stacked(1);
1981 //: if (count >= Operand(1) || Textpos() == mark && count >= 0)
1982 //: { // Max loops or empty match -> straight now
1983 //: Track2(mark, count); // Save old mark, count
1984 //: Advance(2); // Straight
1987 //: { // Nonempty match -> count+loop now
1988 //: Track(mark); // remember mark
1989 //: Stack(Textpos(), count + 1); // Make new mark, incr count
1990 //: Goto(Operand(0)); // Loop
1992 //: continue Forward;
1994 LocalBuilder count = _tempV;
1995 LocalBuilder mark = _temp2V;
1996 Label l1 = DefineLabel();
1997 Label l2 = DefineLabel();
2000 Stloc(count); // count -> temp
2003 Stloc(mark); // mark -> temp2
2007 Bne(l1); // mark != textpos -> l1
2010 Bge(l2); // count >= 0 && mark == textpos -> l2
2015 Bge(l2); // count >= Operand(1) -> l2
2018 PushStack(_textposV);
2020 Ldloc(count); // mark already on track
2027 // if (count >= Operand(1) || Textpos() == mark)
2029 PushTrack(count); // mark already on track
2030 TrackUnique2(branchcountback2);
2034 case RegexCode.Branchcount | RegexCode.Back:
2037 //: if (Stacked(1) > 0) // Positive -> can go straight
2039 //: Textto(Stacked(0)); // Zap to mark
2040 //: Track2(Tracked(0), Stacked(1) - 1); // Save old mark, old count
2041 //: Advance(2); // Straight
2042 //: continue Forward;
2044 //: Stack(Tracked(0), Stacked(1) - 1); // recall old mark, old count
2048 LocalBuilder count = _tempV;
2049 Label l1 = DefineLabel();
2061 PushTrack(count); // Tracked(0) is alredy on the track
2062 TrackUnique2(branchcountback2);
2067 ReadyReplaceStack(0);
2075 case RegexCode.Branchcount | RegexCode.Back2:
2077 //: Stack(Tracked(0), Tracked(1)); // Recall old mark, old count
2078 //: break Backward; // Backtrack
2089 case RegexCode.Lazybranchcount:
2091 //: int mark = Stacked(0);
2092 //: int count = Stacked(1);
2095 //: { // Negative count -> loop now
2096 //: Track2(mark); // Save old mark
2097 //: Stack(Textpos(), count + 1); // Make new mark, incr count
2098 //: Goto(Operand(0)); // Loop
2101 //: { // Nonneg count or empty match -> straight now
2102 //: Track(mark, count, Textpos()); // Save mark, count, position
2105 LocalBuilder count = _tempV;
2106 LocalBuilder mark = _temp2V;
2107 Label l1 = DefineLabel();
2108 #pragma warning disable 219
2109 Label l2 = DefineLabel();
2110 Label l3 = _labels[NextCodepos()];
2111 #pragma warning restore 219
2114 Stloc(count); // count -> temp
2116 Stloc(mark); // mark -> temp2
2120 Bge(l1); // count >= 0 -> l1
2124 PushStack(_textposV);
2130 TrackUnique2(lazybranchcountback2);
2137 PushTrack(_textposV);
2142 case RegexCode.Lazybranchcount | RegexCode.Back:
2144 //: int mark = Tracked(0);
2145 //: int textpos = Tracked(2);
2146 //: if (Tracked(1) < Operand(1) && textpos != mark)
2147 //: { // Under limit and not empty match -> loop
2148 //: Textto(Tracked(2)); // Recall position
2149 //: Stack(Textpos(), Tracked(1) + 1); // Make new mark, incr count
2150 //: Track2(Tracked(0)); // Save old mark
2151 //: Goto(Operand(0)); // Loop
2152 //: continue Forward;
2156 //: Stack(Tracked(0), Tracked(1)); // Recall old mark, count
2157 //: break Backward; // backtrack
2160 Label l1 = DefineLabel();
2161 LocalBuilder cV = _tempV;
2168 Bge(l1); // Tracked(1) >= Operand(1) -> l1
2172 Beq(l1); // textpos == mark -> l1
2174 PushStack(_textposV);
2180 TrackUnique2(lazybranchcountback2);
2192 case RegexCode.Lazybranchcount | RegexCode.Back2:
2199 ReadyReplaceStack(1);
2202 ReadyReplaceStack(0);
2211 case RegexCode.Setjump:
2212 //: Stack(Trackpos(), Crawlpos());
2222 Callvirt(_crawlposM);
2224 TrackUnique(stackpop2);
2227 case RegexCode.Setjump | RegexCode.Back:
2234 case RegexCode.Backjump:
2236 //: Trackto(Stacked(0));
2237 //: while (Crawlpos() != Stacked(1))
2241 Label l1 = DefineLabel();
2242 Label l2 = DefineLabel();
2252 Callvirt(_crawlposM);
2257 Callvirt(_uncaptureM);
2260 Callvirt(_crawlposM);
2269 case RegexCode.Forejump:
2271 //: Trackto(Stacked(0));
2272 //: Track(Stacked(1));
2281 TrackUnique(forejumpback);
2284 case RegexCode.Forejump | RegexCode.Back:
2286 //: while (Crawlpos() != Tracked(0))
2290 Label l1 = DefineLabel();
2291 Label l2 = DefineLabel();
2297 Callvirt(_crawlposM);
2302 Callvirt(_uncaptureM);
2305 Callvirt(_crawlposM);
2315 //: if (Leftchars() > 0 && CharAt(Textpos() - 1) != '\n')
2318 Label l1 = _labels[NextCodepos()];
2329 //: if (Rightchars() > 0 && CharAt(Textpos()) != '\n')
2332 Label l1 = _labels[NextCodepos()];
2342 case RegexCode.Boundary:
2343 case RegexCode.Nonboundary:
2344 //: if (!IsBoundary(Textpos(), _textbeg, _textend))
2350 Callvirt(_isboundaryM);
2351 if (Code() == RegexCode.Boundary)
2352 BrfalseFar(_backtrack);
2354 BrtrueFar(_backtrack);
2357 case RegexCode.ECMABoundary:
2358 case RegexCode.NonECMABoundary:
2359 //: if (!IsECMABoundary(Textpos(), _textbeg, _textend))
2365 Callvirt(_isECMABoundaryM);
2366 if (Code() == RegexCode.ECMABoundary)
2367 BrfalseFar(_backtrack);
2369 BrtrueFar(_backtrack);
2372 case RegexCode.Beginning:
2373 //: if (Leftchars() > 0)
2380 case RegexCode.Start:
2381 //: if (Textpos() != Textstart())
2384 Ldthisfld(_textstartF);
2388 case RegexCode.EndZ:
2389 //: if (Rightchars() > 1 || Rightchars() == 1 && CharAt(Textpos()) != '\n')
2398 Bge(_labels[NextCodepos()]);
2405 //: if (Rightchars() > 0)
2413 case RegexCode.Notone:
2415 case RegexCode.One | RegexCode.Rtl:
2416 case RegexCode.Notone | RegexCode.Rtl:
2417 case RegexCode.Set | RegexCode.Rtl:
2418 case RegexCode.One | RegexCode.Ci:
2419 case RegexCode.Notone | RegexCode.Ci:
2420 case RegexCode.Set | RegexCode.Ci:
2421 case RegexCode.One | RegexCode.Ci | RegexCode.Rtl:
2422 case RegexCode.Notone | RegexCode.Ci | RegexCode.Rtl:
2423 case RegexCode.Set | RegexCode.Ci | RegexCode.Rtl:
2425 //: if (Rightchars() < 1 || Rightcharnext() != (char)Operand(0))
2443 if (Code() == RegexCode.Set) {
2445 Ldstr(_strings[Operand(0)]);
2448 BrfalseFar(_backtrack);
2452 if (Code() == RegexCode.One)
2459 case RegexCode.Multi:
2460 case RegexCode.Multi | RegexCode.Ci:
2469 //: String Str = _strings[Operand(0)];
2471 //: if (Rightchars() < (c = Str.Length))
2473 //: for (i = 0; c > 0; i++, c--)
2474 //: if (Str[i] != Rightcharnext())
2480 str = _strings[Operand(0)];
2488 // unroll the string
2489 for (i = 0; i < str.Length; i++) {
2496 Callvirt(_getcharM);
2512 case RegexCode.Multi | RegexCode.Rtl:
2513 case RegexCode.Multi | RegexCode.Ci | RegexCode.Rtl:
2514 //: String Str = _strings[Operand(0)];
2516 //: if (Leftchars() < (c = Str.Length))
2519 //: if (Str[--c] != Leftcharnext())
2525 str = _strings[Operand(0)];
2533 // unroll the string
2534 for (i = str.Length; i > 0;) {
2538 Ldc(str.Length - i);
2540 Callvirt(_getcharM);
2558 case RegexCode.Ref | RegexCode.Rtl:
2559 case RegexCode.Ref | RegexCode.Ci:
2560 case RegexCode.Ref | RegexCode.Ci | RegexCode.Rtl:
2561 //: int capnum = Operand(0);
2563 //: if (!_match.IsMatched(capnum)) {
2564 //: if (!RegexOptions.ECMAScript)
2567 //: if (Rightchars() < (c = _match.MatchLength(capnum)))
2569 //: for (j = _match.MatchIndex(capnum); c > 0; j++, c--)
2570 //: if (CharAt(j) != Rightcharnext())
2574 LocalBuilder lenV = _tempV;
2575 LocalBuilder indexV = _temp2V;
2576 Label l1 = DefineLabel();
2580 Callvirt(_ismatchedM);
2581 if ((_options & RegexOptions.ECMAScript) != 0)
2582 Brfalse(AdvanceLabel());
2584 BrfalseFar(_backtrack); // !IsMatched() -> back
2588 Callvirt(_matchlengthM);
2600 BgtFar(_backtrack); // Matchlength() > Rightchars() -> back
2604 Callvirt(_matchindexM);
2609 Stloc(indexV); // index += len
2614 Stloc(_textposV); // texpos += len
2619 Ble(AdvanceLabel());
2630 Callvirt(_getcharM);
2644 Callvirt(_getcharM);
2654 case RegexCode.Onerep:
2655 case RegexCode.Notonerep:
2656 case RegexCode.Setrep:
2657 case RegexCode.Onerep | RegexCode.Rtl:
2658 case RegexCode.Notonerep | RegexCode.Rtl:
2659 case RegexCode.Setrep | RegexCode.Rtl:
2660 case RegexCode.Onerep | RegexCode.Ci:
2661 case RegexCode.Notonerep | RegexCode.Ci:
2662 case RegexCode.Setrep | RegexCode.Ci:
2663 case RegexCode.Onerep | RegexCode.Ci | RegexCode.Rtl:
2664 case RegexCode.Notonerep | RegexCode.Ci | RegexCode.Rtl:
2665 case RegexCode.Setrep | RegexCode.Ci | RegexCode.Rtl:
2666 //: int c = Operand(1);
2667 //: if (Rightchars() < c)
2669 //: char ch = (char)Operand(0);
2671 //: if (Rightcharnext() != ch)
2674 LocalBuilder lenV = _tempV;
2675 Label l1 = DefineLabel();
2692 BgtFar(_backtrack); // Matchlength() > Rightchars() -> back
2697 Stloc(_textposV); // texpos += len
2720 Callvirt(_getcharM);
2724 if (Code() == RegexCode.Setrep) {
2725 Ldstr(_strings[Operand(0)]);
2728 BrfalseFar(_backtrack);
2732 if (Code() == RegexCode.Onerep)
2739 if (Code() == RegexCode.Setrep)
2747 case RegexCode.Oneloop:
2748 case RegexCode.Notoneloop:
2749 case RegexCode.Setloop:
2750 case RegexCode.Oneloop | RegexCode.Rtl:
2751 case RegexCode.Notoneloop | RegexCode.Rtl:
2752 case RegexCode.Setloop | RegexCode.Rtl:
2753 case RegexCode.Oneloop | RegexCode.Ci:
2754 case RegexCode.Notoneloop | RegexCode.Ci:
2755 case RegexCode.Setloop | RegexCode.Ci:
2756 case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Rtl:
2757 case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Rtl:
2758 case RegexCode.Setloop | RegexCode.Ci | RegexCode.Rtl:
2759 //: int c = Operand(1);
2760 //: if (c > Rightchars())
2761 //: c = Rightchars();
2762 //: char ch = (char)Operand(0);
2764 //: for (i = c; i > 0; i--)
2766 //: if (Rightcharnext() != ch)
2773 //: Track(c - i - 1, Textpos() - 1);
2776 LocalBuilder cV = _tempV;
2777 LocalBuilder lenV = _temp2V;
2778 Label l1 = DefineLabel();
2779 Label l2 = DefineLabel();
2794 if (c != Int32.MaxValue) {
2795 Label l4 = DefineLabel();
2816 if (Code() == RegexCode.Setloop)
2828 if (Code() == RegexCode.Setloop) {
2829 Ldstr(_strings[Operand(0)]);
2836 if (Code() == RegexCode.Oneloop)
2850 Ble(AdvanceLabel());
2870 case RegexCode.Oneloop | RegexCode.Back:
2871 case RegexCode.Notoneloop | RegexCode.Back:
2872 case RegexCode.Setloop | RegexCode.Back:
2873 case RegexCode.Oneloop | RegexCode.Rtl | RegexCode.Back:
2874 case RegexCode.Notoneloop | RegexCode.Rtl | RegexCode.Back:
2875 case RegexCode.Setloop | RegexCode.Rtl | RegexCode.Back:
2876 case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Back:
2877 case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Back:
2878 case RegexCode.Setloop | RegexCode.Ci | RegexCode.Back:
2879 case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2880 case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2881 case RegexCode.Setloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2883 //: int i = Tracked(0);
2884 //: int pos = Tracked(1);
2887 //: Track(i - 1, pos - 1);
2895 BleFar(AdvanceLabel());
2910 case RegexCode.Onelazy:
2911 case RegexCode.Notonelazy:
2912 case RegexCode.Setlazy:
2913 case RegexCode.Onelazy | RegexCode.Rtl:
2914 case RegexCode.Notonelazy | RegexCode.Rtl:
2915 case RegexCode.Setlazy | RegexCode.Rtl:
2916 case RegexCode.Onelazy | RegexCode.Ci:
2917 case RegexCode.Notonelazy | RegexCode.Ci:
2918 case RegexCode.Setlazy | RegexCode.Ci:
2919 case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Rtl:
2920 case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Rtl:
2921 case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Rtl:
2922 //: int c = Operand(1);
2923 //: if (c > Rightchars())
2924 //: c = Rightchars();
2926 //: Track(c - 1, Textpos());
2928 LocalBuilder cV = _tempV;
2944 if (c != Int32.MaxValue) {
2945 Label l4 = DefineLabel();
2956 Ble(AdvanceLabel());
2962 PushTrack(_textposV);
2967 case RegexCode.Onelazy | RegexCode.Back:
2968 case RegexCode.Notonelazy | RegexCode.Back:
2969 case RegexCode.Setlazy | RegexCode.Back:
2970 case RegexCode.Onelazy | RegexCode.Rtl | RegexCode.Back:
2971 case RegexCode.Notonelazy | RegexCode.Rtl | RegexCode.Back:
2972 case RegexCode.Setlazy | RegexCode.Rtl | RegexCode.Back:
2973 case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Back:
2974 case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Back:
2975 case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Back:
2976 case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2977 case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2978 case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back:
2980 //: int pos = Tracked(1);
2982 //: if (Rightcharnext() != (char)Operand(0))
2984 //: int i = Tracked(0);
2986 //: Track(i - 1, pos + 1);
3001 if (Code() == RegexCode.Setlazy) {
3002 Ldstr(_strings[Operand(0)]);
3005 BrfalseFar(_backtrack);
3009 if (Code() == RegexCode.Onelazy)
3017 BleFar(AdvanceLabel());
3023 PushTrack(_textposV);
3029 throw new NotImplementedException(SR.GetString(SR.UnimplementedState));
3034 internal class RegexTypeCompiler : RegexCompiler {
3035 private static int _typeCount = 0;
3036 private static LocalDataStoreSlot _moduleSlot = Thread.AllocateDataSlot();
3038 private AssemblyBuilder _assembly;
3039 private ModuleBuilder _module;
3041 // state of the type builder
3042 private TypeBuilder _typebuilder;
3043 private MethodBuilder _methbuilder;
3045 [ResourceExposure(ResourceScope.Machine)]
3046 [ResourceConsumption(ResourceScope.Machine)]
3047 [SuppressMessage("Microsoft.Security","CA2106:SecureAsserts", Justification="[....]: SECREVIEW : Regex only generates string manipulation, so this is OK")]
3048 internal RegexTypeCompiler(AssemblyName an, CustomAttributeBuilder[] attribs, String resourceFile) {
3049 // SECREVIEW : Regex only generates string manipulation, so this is
3052 #if !DISABLE_CAS_USE
3053 new ReflectionPermission(PermissionState.Unrestricted).Assert();
3056 Debug.Assert(an != null, "AssemblyName should not be null");
3058 List<CustomAttributeBuilder> assemblyAttributes = new List<CustomAttributeBuilder>();
3060 ConstructorInfo transparencyCtor = typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes);
3061 CustomAttributeBuilder transparencyAttribute = new CustomAttributeBuilder(transparencyCtor, new object[0]);
3062 assemblyAttributes.Add(transparencyAttribute);
3064 #if !DISABLE_CAS_USE
3065 ConstructorInfo securityRulesCtor = typeof(SecurityRulesAttribute).GetConstructor(new Type[] { typeof(SecurityRuleSet) });
3066 CustomAttributeBuilder securityRulesAttribute =
3067 new CustomAttributeBuilder(securityRulesCtor, new object[] { SecurityRuleSet.Level2 });
3068 assemblyAttributes.Add(securityRulesAttribute);
3071 _assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyAttributes);
3072 _module = _assembly.DefineDynamicModule(an.Name + ".dll");
3074 if (attribs != null) {
3075 for (int i=0; i<attribs.Length; i++) {
3076 _assembly.SetCustomAttribute(attribs[i]);
3080 if (resourceFile != null) {
3082 // unmanaged resources are not supported
3083 throw new ArgumentOutOfRangeException("resourceFile");
3085 _assembly.DefineUnmanagedResource(resourceFile);
3090 #if !DISABLE_CAS_USE
3091 CodeAccessPermission.RevertAssert();
3097 * The top-level driver. Initializes everything then calls the Generate* methods.
3099 internal Type FactoryTypeFromCode(RegexCode code, RegexOptions options, String typeprefix) {
3100 String runnertypename;
3101 String runnerfactoryname;
3106 _codes = code._codes;
3107 _strings = code._strings;
3108 _fcPrefix = code._fcPrefix;
3109 _bmPrefix = code._bmPrefix;
3110 _anchors = code._anchors;
3111 _trackcount = code._trackcount;
3114 // pick a name for the class
3115 int typenum = Interlocked.Increment(ref _typeCount);
3116 string typenumString = typenum.ToString(CultureInfo.InvariantCulture);
3117 runnertypename = typeprefix + "Runner" + typenumString ;
3118 runnerfactoryname = typeprefix + "Factory" + typenumString;
3120 // Generate a RegexRunner class
3121 // (blocks are simply illustrative)
3123 DefineType(runnertypename, false, typeof(RegexRunner));
3125 DefineMethod("Go", null);
3131 DefineMethod("FindFirstChar", typeof(bool));
3133 GenerateFindFirstChar();
3137 DefineMethod("InitTrackCount", null);
3139 GenerateInitTrackCount();
3143 runnertype = BakeType();
3146 // Generate a RegexRunnerFactory class
3148 DefineType(runnerfactoryname, false, typeof(RegexRunnerFactory));
3150 DefineMethod("CreateInstance", typeof(RegexRunner));
3152 GenerateCreateInstance(runnertype);
3156 factory = BakeType();
3162 internal void GenerateRegexType(String pattern, RegexOptions opts, String name, bool ispublic, RegexCode code, RegexTree tree, Type factory, TimeSpan matchTimeout) {
3163 FieldInfo patternF = RegexField("pattern");
3164 FieldInfo optionsF = RegexField("roptions");
3165 FieldInfo factoryF = RegexField("factory");
3166 FieldInfo capsF = RegexField("caps");
3167 FieldInfo capnamesF = RegexField("capnames");
3168 FieldInfo capslistF = RegexField("capslist");
3169 FieldInfo capsizeF = RegexField("capsize");
3170 FieldInfo internalMatchTimeoutF = RegexField("internalMatchTimeout");
3171 Type[] noTypeArray = new Type[0];
3172 ConstructorBuilder defCtorBuilder, tmoutCtorBuilder;
3174 DefineType(name, ispublic, typeof(Regex));
3176 // Define default constructor:
3177 _methbuilder = null;
3178 MethodAttributes ma = System.Reflection.MethodAttributes.Public;
3179 defCtorBuilder = _typebuilder.DefineConstructor(ma, CallingConventions.Standard, noTypeArray);
3180 _ilg = defCtorBuilder.GetILGenerator();
3182 // call base constructor
3184 _ilg.Emit(OpCodes.Call, typeof(Regex).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
3185 null, new Type[0], new ParameterModifier[0]));
3196 // Set timeout (no need to validate as it should have happened in RegexCompilationInfo):
3198 LdcI8(matchTimeout.Ticks);
3199 Call(typeof(TimeSpan).GetMethod("FromTicks", BindingFlags.Static | BindingFlags.Public));
3200 Stfld(internalMatchTimeoutF);
3204 Newobj(factory.GetConstructor(noTypeArray));
3208 if (code._caps != null)
3210 GenerateCreateType(typeof(Dictionary<Int32, Int32>), capsF, code._caps);
3212 GenerateCreateHashtable(capsF, code._caps);
3216 if (tree._capnames != null)
3218 GenerateCreateType(typeof(Dictionary<String, Int32>), capnamesF, tree._capnames);
3220 GenerateCreateHashtable(capnamesF, tree._capnames);
3225 if (tree._capslist != null) {
3227 Ldc(tree._capslist.Length);
3228 _ilg.Emit(OpCodes.Newarr, typeof(String)); // create new string array
3231 for (int i=0; i< tree._capslist.Length; i++) {
3232 Ldthisfld(capslistF);
3235 Ldstr(tree._capslist[i]);
3236 _ilg.Emit(OpCodes.Stelem_Ref);
3245 // set runnerref and replref by calling InitializeReferences()
3247 Call(typeof(Regex).GetMethod("InitializeReferences", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
3253 // Constructor with the timeout parameter:
3254 _methbuilder = null;
3255 ma = System.Reflection.MethodAttributes.Public;
3256 tmoutCtorBuilder = _typebuilder.DefineConstructor(ma, CallingConventions.Standard, new Type[] { typeof(TimeSpan) });
3257 _ilg = tmoutCtorBuilder.GetILGenerator();
3259 // Call the default constructor:
3261 _ilg.Emit(OpCodes.Call, defCtorBuilder);
3263 // Validate timeout:
3264 _ilg.Emit(OpCodes.Ldarg_1);
3265 Call(typeof(Regex).GetMethod("ValidateMatchTimeout", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
3269 _ilg.Emit(OpCodes.Ldarg_1);
3270 Stfld(internalMatchTimeoutF);
3276 // bake the constructor and type, then save the assembly
3277 defCtorBuilder = null;
3278 tmoutCtorBuilder = null;
3279 _typebuilder.CreateType();
3281 _typebuilder = null;
3285 internal void GenerateCreateType<TKey>(Type myCollectionType, FieldInfo field, Dictionary<TKey,int> ht) {
3286 MethodInfo addMethod = myCollectionType.GetMethod("Add", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
3289 Newobj(myCollectionType.GetConstructor(new Type[0]));
3291 internal void GenerateCreateHashtable(FieldInfo field, Hashtable ht) {
3292 MethodInfo addMethod = typeof(Hashtable).GetMethod("Add", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
3295 Newobj(typeof(Hashtable).GetConstructor(new Type[0]));
3300 IDictionaryEnumerator en = ht.GetEnumerator();
3301 while (en.MoveNext()) {
3304 if (en.Key is int) {
3307 _ilg.Emit(OpCodes.Box, typeof(Int32));
3311 Ldstr((String) en.Key);
3313 Ldc((int) en.Value);
3315 _ilg.Emit(OpCodes.Box, typeof(Int32));
3317 Callvirt(addMethod);
3321 private FieldInfo RegexField(String fieldname) {
3322 return typeof(Regex).GetField(fieldname, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
3325 // Note that we save the assembly to the current directory, and we believe this is not a
3326 // problem because this should only be used by tools, not at runtime.
3327 [ResourceExposure(ResourceScope.None)]
3328 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
3329 internal void Save() {
3330 _assembly.Save(_assembly.GetName().Name + ".dll");
3334 * Generates a very simple factory method.
3336 internal void GenerateCreateInstance(Type newtype) {
3337 Newobj(newtype.GetConstructor(new Type[0]));
3342 * Begins the definition of a new type with a specified base class
3344 internal void DefineType(String typename, bool ispublic, Type inheritfromclass) {
3346 _typebuilder = _module.DefineType(typename, TypeAttributes.Class | TypeAttributes.Public, inheritfromclass);
3348 _typebuilder = _module.DefineType(typename, TypeAttributes.Class | TypeAttributes.NotPublic, inheritfromclass);
3353 * Begins the definition of a new method (no args) with a specified return value
3355 internal void DefineMethod(String methname, Type returntype) {
3356 MethodAttributes ma = System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Virtual;
3358 _methbuilder = _typebuilder.DefineMethod(methname, ma, returntype, null);
3359 _ilg = _methbuilder.GetILGenerator();
3363 * Ends the definition of a method
3365 internal void BakeMethod() {
3366 _methbuilder = null;
3370 * Ends the definition of a class and returns the type
3372 internal Type BakeType() {
3373 Type retval = _typebuilder.CreateType();
3374 _typebuilder = null;
3381 internal class RegexLWCGCompiler : RegexCompiler {
3382 private static int _regexCount = 0;
3383 private static Type[] _paramTypes = new Type[] {typeof(RegexRunner)};
3385 internal RegexLWCGCompiler() {
3389 * The top-level driver. Initializes everything then calls the Generate* methods.
3391 internal RegexRunnerFactory FactoryInstanceFromCode(RegexCode code, RegexOptions options) {
3393 _codes = code._codes;
3394 _strings = code._strings;
3395 _fcPrefix = code._fcPrefix;
3396 _bmPrefix = code._bmPrefix;
3397 _anchors = code._anchors;
3398 _trackcount = code._trackcount;
3401 // pick a unique number for the methods we generate
3402 int regexnum = Interlocked.Increment(ref _regexCount);
3403 string regexnumString = regexnum.ToString(CultureInfo.InvariantCulture);
3405 DynamicMethod goMethod = DefineDynamicMethod("Go" + regexnumString, null, typeof(CompiledRegexRunner));
3408 DynamicMethod firstCharMethod = DefineDynamicMethod("FindFirstChar" + regexnumString, typeof(bool), typeof(CompiledRegexRunner));
3409 GenerateFindFirstChar();
3411 DynamicMethod trackCountMethod = DefineDynamicMethod("InitTrackCount" + regexnumString, null, typeof(CompiledRegexRunner));
3412 GenerateInitTrackCount();
3414 return new CompiledRegexRunnerFactory(goMethod, firstCharMethod, trackCountMethod);
3418 * Begins the definition of a new method (no args) with a specified return value
3420 internal DynamicMethod DefineDynamicMethod(String methname, Type returntype, Type hostType) {
3421 // We're claiming that these are static methods, but really they are instance methods.
3422 // By giving them a parameter which represents "this", we're tricking them into
3423 // being instance methods.
3425 MethodAttributes attribs = MethodAttributes.Public | MethodAttributes.Static;
3426 CallingConventions conventions = CallingConventions.Standard;
3428 DynamicMethod dm = new DynamicMethod(methname, attribs, conventions, returntype, _paramTypes, hostType, false /*skipVisibility*/);
3429 _ilg = dm.GetILGenerator();