BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / System / System.Text.RegularExpressions / CILCompiler.cs
1 using System;
2 using System.Collections;
3 using System.Globalization;
4 using System.Reflection;
5 using System.Reflection.Emit;
6 using System.Threading;
7
8 #if NET_2_0
9 using System.Collections.Generic;
10 #endif
11
12 namespace System.Text.RegularExpressions {
13
14         //
15         // Compiler which generates IL bytecode to perform the matching instead of
16         // interpreting a program.
17         // For simplicity, we inherit from RxCompiler, and generate the IL code based
18         // on the program generated by it. This also allows us to fallback to interpretation
19         // if we can't handle something.
20         // This is net 2.0, since 1.0 doesn't support DynamicMethods
21         // FIXME: Add support for 1.0, and CompileToAssembly
22         // FIXME: Overwrite RxCompiler methods so we don't have to decode char
23         // matching opcodes
24         //
25
26 #if NET_2_0
27         class CILCompiler : RxCompiler, ICompiler {
28                 DynamicMethod[] eval_methods;
29                 bool[] eval_methods_defined;
30
31                 /*
32                  * To avoid the overhead of decoding the countless opcode variants created
33                  * by RxCompiler, we save the original, 'generic' version and its flags
34                  * in these two tables.
35                  */
36                 private Dictionary<int, int> generic_ops;
37                 private Dictionary<int, int> op_flags;
38                 private Dictionary<int, Label> labels;
39
40                 static FieldInfo fi_str = typeof (RxInterpreter).GetField ("str", BindingFlags.Instance|BindingFlags.NonPublic);
41                 static FieldInfo fi_string_start = typeof (RxInterpreter).GetField ("string_start", BindingFlags.Instance|BindingFlags.NonPublic);
42                 static FieldInfo fi_string_end = typeof (RxInterpreter).GetField ("string_end", BindingFlags.Instance|BindingFlags.NonPublic);
43                 static FieldInfo fi_program = typeof (RxInterpreter).GetField ("program", BindingFlags.Instance|BindingFlags.NonPublic);
44                 static FieldInfo fi_marks = typeof (RxInterpreter).GetField ("marks", BindingFlags.Instance|BindingFlags.NonPublic);
45                 static FieldInfo fi_groups = typeof (RxInterpreter).GetField ("groups", BindingFlags.Instance|BindingFlags.NonPublic);
46                 static FieldInfo fi_deep = typeof (RxInterpreter).GetField ("deep", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
47                 static FieldInfo fi_stack = typeof (RxInterpreter).GetField ("stack", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
48                 static FieldInfo fi_mark_start = typeof (Mark).GetField ("Start", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
49                 static FieldInfo fi_mark_end = typeof (Mark).GetField ("End", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
50                 //static FieldInfo fi_mark_index = typeof (Mark).GetField ("Index", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
51
52                 static MethodInfo mi_stack_get_count, mi_stack_set_count, mi_stack_push, mi_stack_pop;
53                 static MethodInfo mi_set_start_of_match, mi_is_word_char, mi_reset_groups;
54                 static MethodInfo mi_checkpoint, mi_backtrack, mi_open, mi_close;
55                 static MethodInfo mi_get_last_defined, mi_mark_get_index, mi_mark_get_length;
56
57                 public static readonly bool trace_compile = Environment.GetEnvironmentVariable ("MONO_TRACE_RX_COMPILE") != null;
58
59                 public CILCompiler () {
60                         generic_ops = new Dictionary <int, int> ();
61                         op_flags = new Dictionary <int, int> ();
62                 }
63
64                 IMachineFactory ICompiler.GetMachineFactory () {
65                         byte[] code = new byte [curpos];
66                         Buffer.BlockCopy (program, 0, code, 0, curpos);
67
68                         eval_methods = new DynamicMethod [code.Length];
69                         eval_methods_defined = new bool [code.Length];
70
71                         // The main eval method
72                     DynamicMethod main = GetEvalMethod (code, 11);
73
74                         if (main != null)
75                                 return new RxInterpreterFactory (code, (EvalDelegate)main.CreateDelegate (typeof (EvalDelegate)));
76                         else
77                                 return new RxInterpreterFactory (code, null);
78                 }
79
80                 DynamicMethod GetEvalMethod (byte[] program, int pc) {
81                         if (eval_methods_defined [pc])
82                                 return eval_methods [pc];
83
84                         // FIXME: Recursion ?
85                         eval_methods_defined [pc] = true;
86
87                         eval_methods [pc] = CreateEvalMethod (program, pc);
88                         return eval_methods [pc];
89                 }
90
91                 private MethodInfo GetMethod (Type t, string name, ref MethodInfo cached) {
92                         if (cached == null) {
93                                 cached = t.GetMethod (name, BindingFlags.Static|BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
94                                 if (cached == null)
95                                         throw new Exception ("Method not found: " + name);
96                         }
97                         return cached;
98                 }
99
100                 private MethodInfo GetMethod (string name, ref MethodInfo cached) {
101                         return GetMethod (typeof (RxInterpreter), name, ref cached);
102             }
103
104                 private int ReadInt (byte[] code, int pc) {
105                         int val = code [pc];
106                         val |= code [pc + 1] << 8;
107                         val |= code [pc + 2] << 16;
108                         val |= code [pc + 3] << 24;
109                         return val;
110                 }
111
112                 static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) {
113                         OpFlags flags = 0;
114                         if (negate) flags |= OpFlags.Negate;
115                         if (ignore) flags |= OpFlags.IgnoreCase;
116                         if (reverse) flags |= OpFlags.RightToLeft;
117                         if (lazy) flags |= OpFlags.Lazy;
118
119                         return flags;
120                 }
121
122                 void EmitGenericOp (RxOp op, bool negate, bool ignore, bool reverse, bool lazy) {
123                         generic_ops [curpos] = (int)op;
124                         op_flags [curpos] = (int)MakeFlags (negate, ignore, reverse, false);
125             }
126
127                 public override void EmitOp (RxOp op, bool negate, bool ignore, bool reverse) {
128                         EmitGenericOp (op, negate, ignore, reverse, false);
129                         base.EmitOp (op, negate, ignore, reverse);
130                 }
131
132                 public override void EmitOpIgnoreReverse (RxOp op, bool ignore, bool reverse) {
133                         EmitGenericOp (op, false, ignore, reverse, false);
134                         base.EmitOpIgnoreReverse (op, ignore, reverse);
135                 }
136
137                 public override void EmitOpNegateReverse (RxOp op, bool negate, bool reverse) {
138                         EmitGenericOp (op, negate, false, reverse, false);
139                         base.EmitOpNegateReverse (op, negate, reverse);
140                 }
141
142                 class Frame {
143                         public Label label_pass, label_fail;
144
145                         public Frame (ILGenerator ilgen) {
146                                 label_fail = ilgen.DefineLabel ();
147                                 label_pass = ilgen.DefineLabel ();
148                         }                               
149                 }
150
151                 LocalBuilder local_textinfo;
152
153                 /*
154                  * Create a dynamic method which is equivalent to the RxInterpreter.EvalByteCode 
155                  * method specialized to the given program and a given pc. Return the newly
156                  * created method or null if a not-supported opcode was encountered.
157                  */
158                 DynamicMethod CreateEvalMethod (byte[] program, int pc) {
159                         DynamicMethod m = new DynamicMethod ("Eval_" + pc, typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof (int).MakeByRefType () }, typeof (RxInterpreter), true);
160                         ILGenerator ilgen = m.GetILGenerator ();
161
162                         /* 
163                            Args:
164                            interp - 0
165                            strpos - 1
166                            strpos_result - 2
167                         */
168
169                         /*
170                          * Recursive calls to EvalByteCode are inlined manually by calling 
171                          * EmitEvalMethodBody with the pc of the recursive call. Frame objects hold
172                          * the information required to link together the code generated by the recursive
173                          * call with the rest of the code.
174                          */
175                         Frame frame = new Frame (ilgen);
176
177                         /* Cache the textinfo used by Char.ToLower () */
178                         local_textinfo = ilgen.DeclareLocal (typeof (TextInfo));
179                         ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentThread"));
180                         ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentCulture"));
181                         ilgen.Emit (OpCodes.Call, typeof (CultureInfo).GetMethod ("get_TextInfo"));
182                         ilgen.Emit (OpCodes.Stloc, local_textinfo);
183
184                         m = EmitEvalMethodBody (m, ilgen, frame, program, pc, program.Length, false, false, out pc);
185                         if (m == null)
186                                 return null;
187                                 
188                         ilgen.MarkLabel (frame.label_pass);
189                         ilgen.Emit (OpCodes.Ldarg_2);
190                         ilgen.Emit (OpCodes.Ldarg_1);
191                         ilgen.Emit (OpCodes.Stind_I4);
192                         ilgen.Emit (OpCodes.Ldc_I4_1);
193                         ilgen.Emit (OpCodes.Ret);
194
195                         ilgen.MarkLabel (frame.label_fail);
196                         ilgen.Emit (OpCodes.Ldc_I4_0);
197                         ilgen.Emit (OpCodes.Ret);
198
199                         return m;
200                 }
201
202                 private int ReadShort (byte[] program, int pc) {
203                         return (int)program [pc] | ((int)program [pc + 1] << 8);
204                 }
205
206                 private Label CreateLabelForPC (ILGenerator ilgen, int pc) {
207                         if (labels == null)
208                                 labels = new Dictionary <int, Label> ();
209                         Label l;
210                         if (!labels.TryGetValue (pc, out l)) {
211                                 l = ilgen.DefineLabel ();
212                                 labels [pc] = l;
213                         }
214
215                         return l;
216                 }
217
218                 private int GetILOffset (ILGenerator ilgen) {
219                         return (int)typeof (ILGenerator).GetField ("code_len", BindingFlags.Instance|BindingFlags.NonPublic).GetValue (ilgen);
220                 }
221
222                 /*
223                  * Emit IL code for a sequence of opcodes between pc and end_pc. If there is a
224                  * match, set strpos (Arg 1) to the position after the match, then 
225                  * branch to frame.label_pass. Otherwise branch to frame.label_fail, 
226                  * and leave strpos at an undefined position. The caller should 
227                  * generate code to save the original value of strpos if it needs it.
228                  * If one_op is true, only generate code for one opcode and set out_pc 
229                  * to the next pc after the opcode.
230                  * If no_bump is true, don't bump strpos in char matching opcodes.
231                  * Keep this in synch with RxInterpreter.EvalByteCode (). It it is sync with
232                  * the version in r111969.
233                  * FIXME: Modify the regex tests so they are run with RegexOptions.Compiled as
234                  * well.
235                  */
236                 private DynamicMethod EmitEvalMethodBody (DynamicMethod m, ILGenerator ilgen,
237                                                                                                   Frame frame, byte[] program,
238                                                                                                   int pc, int end_pc,
239                                                                                                   bool one_op, bool no_bump,
240                                                                                                   out int out_pc)
241                 {
242                         int start, length, end;
243
244                         out_pc = 0;
245
246                         int group_count = 1 + ReadShort (program, 1);
247
248                         while (pc < end_pc) {
249                                 RxOp op = (RxOp)program [pc];
250
251                                 // FIXME: Optimize this
252                                 if (generic_ops.ContainsKey (pc))
253                                         op = (RxOp)generic_ops [pc];
254
255                                 if (trace_compile) {
256                                         Console.WriteLine ("compiling {0} pc={1} end_pc={2}, il_offset=0x{3:x}", op, pc, end_pc, GetILOffset (ilgen));
257                                 }
258
259                                 if (labels != null) {
260                                         Label l;
261                                         if (labels.TryGetValue (pc, out l)) {
262                                                 ilgen.MarkLabel (l);
263                                                 labels.Remove (pc);
264                                         }
265                                 }
266
267                                 if (RxInterpreter.trace_rx) {
268                                         //Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", op, pc, strpos);
269                                         ilgen.Emit (OpCodes.Ldstr, "evaluating: {0} at pc: {1}, strpos: {2}");
270                                         ilgen.Emit (OpCodes.Ldc_I4, (int)op);
271                                         ilgen.Emit (OpCodes.Box, typeof (RxOp));
272                                         ilgen.Emit (OpCodes.Ldc_I4, pc);
273                                         ilgen.Emit (OpCodes.Box, typeof (int));
274                                         ilgen.Emit (OpCodes.Ldarg_1);
275                                         ilgen.Emit (OpCodes.Box, typeof (int));
276                                         ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object), typeof (object), typeof (object) }));
277                                 }
278
279                                 switch (op) {
280                                 case RxOp.Anchor:
281                                 case RxOp.AnchorReverse: {
282                                         bool reverse = (RxOp)program [pc] == RxOp.AnchorReverse;
283                                         length = ReadShort (program, pc + 3);
284                                         pc += ReadShort (program, pc + 1);
285
286                                         // Optimize some common cases by inlining the code generated for the
287                                         // anchor body 
288                                         RxOp anch_op = (RxOp)program [pc];
289
290                                         // FIXME: Do this even if the archor op is not the last in the regex
291                                         if (!reverse && group_count == 1 && anch_op == RxOp.Char && (RxOp)program [pc + 2] == RxOp.True) {
292
293                                                 /*
294                                                  * while (strpos < string_end) {
295                                                  *   if (str [strpos] == program [pc + 1]) {
296                                                  *     match_start = strpos;
297                                                  *     strpos_result = strpos + 1;
298                                                  *     marks [groups [0]].Start = strpos;
299                                                  *     if (groups.Length > 1)
300                                                  *              marks [groups [0]].End = res;
301                                                  *     return true;
302                                                  *   }
303                                                  *   strpos ++;
304                                                  * }
305                                                  * return false;
306                                                  */
307                                                 // Add some locals to avoid an indirection
308                                                 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
309                                                 ilgen.Emit (OpCodes.Ldarg_0);
310                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
311                                                 ilgen.Emit (OpCodes.Stloc, local_string_end);
312                                                 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
313                                                 ilgen.Emit (OpCodes.Ldarg_0);
314                                                 ilgen.Emit (OpCodes.Ldfld, fi_str);
315                                                 ilgen.Emit (OpCodes.Stloc, local_str);
316
317                                                 //while (strpos < string_end) {
318                                                 // -> Done at the end of the loop like mcs does
319                                                 Label l1 = ilgen.DefineLabel ();
320                                                 Label l2 = ilgen.DefineLabel ();
321                                                 ilgen.Emit (OpCodes.Br, l2);
322                                                 ilgen.MarkLabel (l1);
323
324                                                 //  if (str [strpos] == program [pc + 1]) {
325                                                 Label l3 = ilgen.DefineLabel ();
326                                                 ilgen.Emit (OpCodes.Ldloc, local_str);
327                                                 ilgen.Emit (OpCodes.Ldarg_1);
328                                                 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
329                                                 ilgen.Emit (OpCodes.Conv_I4);
330                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
331                                                 ilgen.Emit (OpCodes.Beq, l3);
332
333                                                 // The true case is done after the loop
334
335                                                 //  }
336                                                 //  strpos++;
337                                                 ilgen.Emit (OpCodes.Ldarg_1);
338                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
339                                                 ilgen.Emit (OpCodes.Add);
340                                                 ilgen.Emit (OpCodes.Starg, 1);
341                                                 //}
342                                                 ilgen.MarkLabel (l2);
343                                                 ilgen.Emit (OpCodes.Ldarg_1);
344                                                 ilgen.Emit (OpCodes.Ldloc, local_string_end);
345                                                 ilgen.Emit (OpCodes.Blt, l1);
346
347                                                 //return false;
348                                                 ilgen.Emit (OpCodes.Br, frame.label_fail);
349
350                                                 // True case
351                                                 ilgen.MarkLabel (l3);
352                                                 // call SetStartOfMatch (strpos)
353                                                 ilgen.Emit (OpCodes.Ldarg_0);
354                                                 ilgen.Emit (OpCodes.Ldarg_1);
355                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "SetStartOfMatch", ref mi_set_start_of_match));
356                                                 //  strpos++;
357                                                 ilgen.Emit (OpCodes.Ldarg_1);
358                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
359                                                 ilgen.Emit (OpCodes.Add);
360                                                 ilgen.Emit (OpCodes.Starg, 1);
361                                                 //    return true;
362                                                 ilgen.Emit (OpCodes.Br, frame.label_pass);
363
364                                         } else {
365                                                 // General case
366
367                                                 //Console.WriteLine ("Anchor op " + anch_op);
368
369                                                 // Add some locals to avoid an indirection
370                                                 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
371                                                 ilgen.Emit (OpCodes.Ldarg_0);
372                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
373                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
374                                                 ilgen.Emit (OpCodes.Add);
375                                                 ilgen.Emit (OpCodes.Stloc, local_string_end);
376
377                                                 //while (strpos < string_end + 1) {
378                                                 // -> Done at the end of the loop like mcs does
379                                                 Label l1 = ilgen.DefineLabel ();
380                                                 Label l2 = ilgen.DefineLabel ();
381                                                 ilgen.Emit (OpCodes.Br, l2);
382                                                 ilgen.MarkLabel (l1);
383
384                                                 //if (groups.Length > 1) {
385                                                 //      ResetGroups ();
386                                                 //      marks [groups [0]].Start = strpos;
387                                                 //}
388                                                 if (group_count > 1) {
389                                                         ilgen.Emit (OpCodes.Ldarg_0);
390                                                         ilgen.Emit (OpCodes.Call, GetMethod ("ResetGroups", ref mi_reset_groups));
391
392                                                         ilgen.Emit (OpCodes.Ldarg_0);
393                                                         ilgen.Emit (OpCodes.Ldfld, fi_marks);
394                                                         ilgen.Emit (OpCodes.Ldarg_0);
395                                                         ilgen.Emit (OpCodes.Ldfld, fi_groups);
396                                                         ilgen.Emit (OpCodes.Ldc_I4_0);
397                                                         ilgen.Emit (OpCodes.Ldelem_I4);
398                                                         ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
399                                                         ilgen.Emit (OpCodes.Ldarg_1);
400                                                         ilgen.Emit (OpCodes.Stfld, fi_mark_start);
401                                                 }
402
403                                                 //  if (EvalByteCode (pc, strpos, ref res)) {
404
405                                                 Frame new_frame = new Frame (ilgen);
406
407                                                 //  old_stros = strpos;
408                                                 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
409                                                 ilgen.Emit (OpCodes.Ldarg_1);
410                                                 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
411
412                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, end_pc, false, false, out out_pc);
413                                                 if (m == null)
414                                                         return null;
415
416                                                 // Pass
417                                                 ilgen.MarkLabel (new_frame.label_pass);
418                                                 //    marks [groups [0]].Start = old_strpos;
419                                                 ilgen.Emit (OpCodes.Ldarg_0);
420                                                 ilgen.Emit (OpCodes.Ldfld, fi_marks);
421                                                 ilgen.Emit (OpCodes.Ldarg_0);
422                                                 ilgen.Emit (OpCodes.Ldfld, fi_groups);
423                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
424                                                 ilgen.Emit (OpCodes.Ldelem_I4);
425                                                 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
426                                                 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
427                                                 ilgen.Emit (OpCodes.Stfld, fi_mark_start);
428                                                 //    if (groups.Length > 1)
429                                                 //              marks [groups [0]].End = res;
430                                                 if (group_count > 1) {
431                                                         ilgen.Emit (OpCodes.Ldarg_0);
432                                                         ilgen.Emit (OpCodes.Ldfld, fi_marks);
433                                                         ilgen.Emit (OpCodes.Ldarg_0);
434                                                         ilgen.Emit (OpCodes.Ldfld, fi_groups);
435                                                         ilgen.Emit (OpCodes.Ldc_I4_0);
436                                                         ilgen.Emit (OpCodes.Ldelem_I4);
437                                                         ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
438                                                         ilgen.Emit (OpCodes.Ldarg_1);
439                                                         ilgen.Emit (OpCodes.Stfld, fi_mark_end);
440                                                 }
441
442                                                 //    return true;
443                                                 ilgen.Emit (OpCodes.Br, frame.label_pass);
444
445                                                 // Fail
446                                                 ilgen.MarkLabel (new_frame.label_fail);
447                                                 //  strpos = old_strpos +/- 1;
448                                                 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
449                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
450                                                 if (reverse)
451                                                         ilgen.Emit (OpCodes.Sub);
452                                                 else
453                                                         ilgen.Emit (OpCodes.Add);
454                                                 ilgen.Emit (OpCodes.Starg, 1);
455                                                 //}
456                                                 ilgen.MarkLabel (l2);
457                                                 if (reverse) {
458                                                         ilgen.Emit (OpCodes.Ldarg_1);
459                                                         ilgen.Emit (OpCodes.Ldc_I4_0);
460                                                         ilgen.Emit (OpCodes.Bge, l1);
461                                                 } else {
462                                                         ilgen.Emit (OpCodes.Ldarg_1);
463                                                         ilgen.Emit (OpCodes.Ldloc, local_string_end);
464                                                         ilgen.Emit (OpCodes.Blt, l1);
465                                                 }
466                                                 //return false;
467                                                 ilgen.Emit (OpCodes.Br, frame.label_fail);
468                                         }
469
470                                         goto End;
471                                 }
472                                 case RxOp.Branch: {
473                                         //if (EvalByteCode (pc + 3, strpos, ref res)) {
474
475                                         int target_pc = pc + ReadShort (program, pc + 1);
476
477                                         // Emit the rest of the code inline instead of making a recursive call
478                                         Frame new_frame = new Frame (ilgen);
479
480                                         //  old_strpos = strpos;
481                                         LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
482                                         ilgen.Emit (OpCodes.Ldarg_1);
483                                         ilgen.Emit (OpCodes.Stloc, local_old_strpos);
484
485                                         m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target_pc, false, false, out out_pc);
486                                         if (m == null)
487                                                 return null;
488
489                                         // Pass
490                                         ilgen.MarkLabel (new_frame.label_pass);
491                                         //  return true;
492                                         ilgen.Emit (OpCodes.Br, frame.label_pass);
493
494                                         // Fail
495                                         ilgen.MarkLabel (new_frame.label_fail);
496                                         //  strpos = old_strpos;
497                                         ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
498                                         ilgen.Emit (OpCodes.Starg, 1);
499
500                                         pc = target_pc;
501                                         break;
502                                 }
503                                 case RxOp.Char:
504                                 case RxOp.UnicodeChar:
505                                 case RxOp.Range:
506                                 case RxOp.UnicodeRange: {
507                                         OpFlags flags = (OpFlags)op_flags [pc];
508                                         bool negate = (flags & OpFlags.Negate) > 0;
509                                         bool ignore = (flags & OpFlags.IgnoreCase) > 0;
510                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
511
512                                         //if (strpos < string_end) {
513                                         Label l1 = ilgen.DefineLabel ();
514                                         if (reverse) {
515                                                 ilgen.Emit (OpCodes.Ldarg_1);
516                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
517                                                 ilgen.Emit (OpCodes.Ble, l1);
518                                         } else {
519                                                 ilgen.Emit (OpCodes.Ldarg_1);
520                                                 ilgen.Emit (OpCodes.Ldarg_0);
521                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
522                                                 ilgen.Emit (OpCodes.Bge, l1);
523                                         }
524
525                                         if (ignore)
526                                                 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
527
528                                         //  int c = str [strpos];
529                                         LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
530                                         ilgen.Emit (OpCodes.Ldarg_0);
531                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
532                                         ilgen.Emit (OpCodes.Ldarg_1);
533                                         if (reverse) {
534                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
535                                                 ilgen.Emit (OpCodes.Sub);
536                                         }
537                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
538                                         if (ignore)
539                                                 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
540
541                                         if (op == RxOp.Char) {
542                                                 ilgen.Emit (OpCodes.Conv_I4);
543                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
544                                                 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
545
546                                                 pc += 2;
547                                         } else if (op == RxOp.UnicodeChar) {
548                                                 ilgen.Emit (OpCodes.Conv_I4);
549                                                 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
550                                                 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
551
552                                                 pc += 3;
553                                         } else if (op == RxOp.Range) {
554                                                 ilgen.Emit (OpCodes.Stloc, local_c);
555
556                                                 //  if (c >= program [pc + 1] && c <= program [pc + 2]) {
557                                                 if (negate) {
558                                                         Label l3 = ilgen.DefineLabel ();
559
560                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
561                                                         ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
562                                                         ilgen.Emit (OpCodes.Blt, l3);
563                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
564                                                         ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
565                                                         ilgen.Emit (OpCodes.Bgt, l3);
566                                                         ilgen.Emit (OpCodes.Br, l1);
567                                                         ilgen.MarkLabel (l3);
568                                                 } else {
569                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
570                                                         ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
571                                                         ilgen.Emit (OpCodes.Blt, l1);
572                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
573                                                         ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
574                                                         ilgen.Emit (OpCodes.Bgt, l1);
575                                                 }
576
577                                                 pc += 3;
578                                         } else if (op == RxOp.UnicodeRange) {
579                                                 ilgen.Emit (OpCodes.Stloc, local_c);
580
581                                                 //  if (c >= program [pc + 1] && c <= program [pc + 2]) {
582                                                 if (negate) {
583                                                         Label l3 = ilgen.DefineLabel ();
584
585                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
586                                                         ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
587                                                         ilgen.Emit (OpCodes.Blt, l3);
588                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
589                                                         ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
590                                                         ilgen.Emit (OpCodes.Bgt, l3);
591                                                         ilgen.Emit (OpCodes.Br, l1);
592                                                         ilgen.MarkLabel (l3);
593                                                 } else {
594                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
595                                                         ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
596                                                         ilgen.Emit (OpCodes.Blt, l1);
597                                                         ilgen.Emit (OpCodes.Ldloc, local_c);
598                                                         ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
599                                                         ilgen.Emit (OpCodes.Bgt, l1);
600                                                 }
601
602                                                 pc += 5;
603                                         } else {
604                                                 throw new NotSupportedException ();
605                                         }
606
607                                         //ilgen.EmitWriteLine ("HIT:" + (char)program [pc + 1]);
608                                         if (!no_bump) {
609                                                 //  strpos++ / strpos--;
610                                                 ilgen.Emit (OpCodes.Ldarg_1);
611                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
612                                                 if (reverse)
613                                                         ilgen.Emit (OpCodes.Sub);
614                                                 else
615                                                         ilgen.Emit (OpCodes.Add);
616                                                 ilgen.Emit (OpCodes.Starg, 1);
617                                         }
618                                         Label l2 = ilgen.DefineLabel ();
619                                         ilgen.Emit (OpCodes.Br, l2);
620                                         //}
621                                         ilgen.MarkLabel (l1);
622                                         //return false;
623                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
624                                         ilgen.MarkLabel (l2);
625
626                                         break;
627                                 }
628                                 case RxOp.True: {
629                                         //  return true;
630                                         ilgen.Emit (OpCodes.Br, frame.label_pass);
631                                         pc++;
632                                         break;
633                                 }
634                                 case RxOp.False: {
635                                         //  return false;
636                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
637                                         pc++;
638                                         break;
639                                 }
640                                 case RxOp.AnyPosition: {
641                                         pc++;
642                                         break;
643                                 }
644                                 case RxOp.StartOfString: {
645                                         //if (strpos != 0)
646                                         //      return false;
647                                         ilgen.Emit (OpCodes.Ldarg_1);
648                                         ilgen.Emit (OpCodes.Ldc_I4_0);
649                                         ilgen.Emit (OpCodes.Bgt, frame.label_fail);
650                                         pc++;
651                                         break;
652                                 }
653                                 case RxOp.StartOfLine: {
654                                         // FIXME: windows line endings
655                                         //if (!(strpos == 0 || str [strpos - 1] == '\n'))
656                                         //      return false;
657                                         Label l = ilgen.DefineLabel ();
658                                         ilgen.Emit (OpCodes.Ldarg_1);
659                                         ilgen.Emit (OpCodes.Ldc_I4_0);
660                                         ilgen.Emit (OpCodes.Beq, l);
661                                         ilgen.Emit (OpCodes.Ldarg_0);
662                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
663                                         ilgen.Emit (OpCodes.Ldarg_1);
664                                         ilgen.Emit (OpCodes.Ldc_I4_1);
665                                         ilgen.Emit (OpCodes.Sub);
666                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
667                                         ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
668                                         ilgen.Emit (OpCodes.Beq, l);
669                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
670                                         ilgen.MarkLabel (l);
671
672                                         pc++;
673                                         break;
674                                 }
675                                 case RxOp.StartOfScan: {
676                                         //if (strpos != string_start)
677                                         //      return false;
678                                         ilgen.Emit (OpCodes.Ldarg_1);
679                                         ilgen.Emit (OpCodes.Ldarg_0);
680                                         ilgen.Emit (OpCodes.Ldfld, fi_string_start);
681                                         ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
682                                         pc++;
683                                         break;
684                                 }
685                                 case RxOp.End: {
686                                         //if (!(strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')))
687                                         //      return false;
688                                         Label l = ilgen.DefineLabel ();
689
690                                         ilgen.Emit (OpCodes.Ldarg_1);
691                                         ilgen.Emit (OpCodes.Ldarg_0);
692                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
693                                         ilgen.Emit (OpCodes.Beq, l);
694
695                                         Label l2 = ilgen.DefineLabel ();
696                                         ilgen.Emit (OpCodes.Ldarg_1);
697                                         ilgen.Emit (OpCodes.Ldarg_0);
698                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
699                                         ilgen.Emit (OpCodes.Ldc_I4_1);
700                                         ilgen.Emit (OpCodes.Sub);
701                                         ilgen.Emit (OpCodes.Bne_Un, l2);
702                                         ilgen.Emit (OpCodes.Ldarg_0);
703                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
704                                         ilgen.Emit (OpCodes.Ldarg_1);
705                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
706                                         ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
707                                         ilgen.Emit (OpCodes.Bne_Un, l2);
708                                         ilgen.Emit (OpCodes.Br, l);
709                                         ilgen.MarkLabel (l2);
710
711                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
712                                         ilgen.MarkLabel (l);
713
714                                         pc++;
715                                         break;
716                                 }
717                                 case RxOp.EndOfString: {
718                                         //if (strpos != string_end)
719                                         //      return false;
720                                         ilgen.Emit (OpCodes.Ldarg_1);
721                                         ilgen.Emit (OpCodes.Ldarg_0);
722                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
723                                         ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
724                                         pc++;
725                                         break;
726                                 }
727                                 case RxOp.EndOfLine: {
728                                         //if (!(strpos == string_end || str [strpos] == '\n'))
729                                         //      return false;
730                                         Label l_match = ilgen.DefineLabel ();
731                                         ilgen.Emit (OpCodes.Ldarg_1);
732                                         ilgen.Emit (OpCodes.Ldarg_0);
733                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
734                                         ilgen.Emit (OpCodes.Beq, l_match);
735                                         ilgen.Emit (OpCodes.Ldarg_0);
736                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
737                                         ilgen.Emit (OpCodes.Ldarg_1);
738                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
739                                         ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
740                                         ilgen.Emit (OpCodes.Beq, l_match);
741                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
742                                         ilgen.MarkLabel (l_match);
743                                         
744                                         pc++;
745                                         break;
746                                 }
747                                 case RxOp.WordBoundary:
748                                 case RxOp.NoWordBoundary: {
749                                         bool negate = op == RxOp.NoWordBoundary;
750
751                                         //if (string_end == 0)
752                                         //      return false;
753                                         ilgen.Emit (OpCodes.Ldarg_0);
754                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
755                                         ilgen.Emit (OpCodes.Ldc_I4_0);
756                                         ilgen.Emit (OpCodes.Beq, frame.label_fail);
757
758                                         Label l_match = ilgen.DefineLabel ();
759
760                                         //if (strpos == 0) {
761                                         Label l1 = ilgen.DefineLabel ();
762                                         ilgen.Emit (OpCodes.Ldarg_1);
763                                         ilgen.Emit (OpCodes.Ldc_I4_0);
764                                         ilgen.Emit (OpCodes.Bne_Un, l1);
765                                         //if (!IsWordChar (str [strpos])) {
766                                         //  return false;
767                                         ilgen.Emit (OpCodes.Ldarg_0);
768                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
769                                         ilgen.Emit (OpCodes.Ldarg_1);
770                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
771                                         ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
772                                         ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
773                                         ilgen.Emit (OpCodes.Br, l_match);
774
775                                         //} else if (strpos == string_end) {
776                                         ilgen.MarkLabel (l1);
777                                         Label l2 = ilgen.DefineLabel ();
778                                         ilgen.Emit (OpCodes.Ldarg_1);
779                                         ilgen.Emit (OpCodes.Ldarg_0);
780                                         ilgen.Emit (OpCodes.Ldfld, fi_string_end);
781                                         ilgen.Emit (OpCodes.Bne_Un, l2);
782                                         //if (!IsWordChar (str [strpos - 1])) {
783                                         //  return false;
784                                         ilgen.Emit (OpCodes.Ldarg_0);
785                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
786                                         ilgen.Emit (OpCodes.Ldarg_1);
787                                         ilgen.Emit (OpCodes.Ldc_I4_1);
788                                         ilgen.Emit (OpCodes.Sub);
789                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
790                                         ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
791                                         ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
792                                         ilgen.Emit (OpCodes.Br, l_match);
793
794                                         //} else {
795                                         ilgen.MarkLabel (l2);
796                                         //if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
797                                         //  return false;
798                                         ilgen.Emit (OpCodes.Ldarg_0);
799                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
800                                         ilgen.Emit (OpCodes.Ldarg_1);
801                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
802                                         ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
803                                         ilgen.Emit (OpCodes.Ldarg_0);
804                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
805                                         ilgen.Emit (OpCodes.Ldarg_1);
806                                         ilgen.Emit (OpCodes.Ldc_I4_1);
807                                         ilgen.Emit (OpCodes.Sub);
808                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
809                                         ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
810                                         ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, frame.label_fail);
811                                         ilgen.Emit (OpCodes.Br, l_match);
812
813                                         ilgen.MarkLabel (l_match);
814
815                                         pc++;
816                                         break;
817                                 }
818                                 case RxOp.Bitmap:
819                                 case RxOp.UnicodeBitmap: {
820                                         OpFlags flags = (OpFlags)op_flags [pc];
821                                         bool negate = (flags & OpFlags.Negate) > 0;
822                                         bool ignore = (flags & OpFlags.IgnoreCase) > 0;
823                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
824                                         bool unicode = (op == RxOp.UnicodeBitmap);
825
826                                         //if (strpos < string_end) {
827                                         Label l1 = ilgen.DefineLabel ();
828                                         Label l2 = ilgen.DefineLabel ();
829                                         Label l_match = ilgen.DefineLabel ();
830                                         if (reverse) {
831                                                 ilgen.Emit (OpCodes.Ldarg_1);
832                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
833                                                 ilgen.Emit (OpCodes.Ble, l1);
834                                         } else {
835                                                 ilgen.Emit (OpCodes.Ldarg_1);
836                                                 ilgen.Emit (OpCodes.Ldarg_0);
837                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
838                                                 ilgen.Emit (OpCodes.Bge, l1);
839                                         }
840                                         //  int c = str [strpos];
841                                         LocalBuilder local_c = ilgen.DeclareLocal (typeof (int));
842                                         if (ignore)
843                                                 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
844                                         ilgen.Emit (OpCodes.Ldarg_0);
845                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
846                                         ilgen.Emit (OpCodes.Ldarg_1);
847                                         if (reverse) {
848                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
849                                                 ilgen.Emit (OpCodes.Sub);
850                                         }
851                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
852                                         ilgen.Emit (OpCodes.Conv_I4);
853                                         if (ignore)
854                                                 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
855                                         //  c -= program [pc + 1];
856                                         if (unicode) {
857                                                 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
858                                                 ilgen.Emit (OpCodes.Sub);
859                                                 ilgen.Emit (OpCodes.Stloc, local_c);
860                                                 length = ReadShort (program, pc + 3);
861                                                 pc += 5;
862                                         } else {
863                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
864                                                 ilgen.Emit (OpCodes.Sub);
865                                                 ilgen.Emit (OpCodes.Stloc, local_c);
866                                                 length =  program [pc + 2];
867                                                 pc += 3;
868                                         }
869                                         //  if (c < 0 || c >= (length << 3))
870                                         //    return false;
871                                         ilgen.Emit (OpCodes.Ldloc, local_c);
872                                         ilgen.Emit (OpCodes.Ldc_I4_0);
873                                         ilgen.Emit (OpCodes.Blt, negate ? l_match : frame.label_fail);
874                                         ilgen.Emit (OpCodes.Ldloc, local_c);
875                                         ilgen.Emit (OpCodes.Ldc_I4, length << 3);
876                                         ilgen.Emit (OpCodes.Bge, negate ? l_match : frame.label_fail);
877
878                                         // Optimized version for small bitmaps
879                                         if (length <= 4) {
880                                                 uint bitmap = program [pc];
881                                                 
882                                                 if (length > 1)
883                                                         bitmap |= ((uint)program [pc + 1] << 8);
884                                                 if (length > 2)
885                                                         bitmap |= ((uint)program [pc + 2] << 16);
886                                                 if (length > 3)
887                                                         bitmap |= ((uint)program [pc + 3] << 24);
888
889                                                 //if ((bitmap >> c) & 1)
890                                                 ilgen.Emit (OpCodes.Ldc_I4, bitmap);
891                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
892                                                 ilgen.Emit (OpCodes.Shr_Un);
893                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
894                                                 ilgen.Emit (OpCodes.And);
895                                                 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, l1);
896                                         } else {
897                                                 //  if ((program [pc + (c >> 3)] & (1 << (c & 0x7))) != 0) {
898                                                 ilgen.Emit (OpCodes.Ldarg_0);
899                                                 ilgen.Emit (OpCodes.Ldfld, fi_program);
900                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
901                                                 ilgen.Emit (OpCodes.Ldc_I4_3);
902                                                 ilgen.Emit (OpCodes.Shr);
903                                                 ilgen.Emit (OpCodes.Ldc_I4, pc);
904                                                 ilgen.Emit (OpCodes.Add);
905                                                 ilgen.Emit (OpCodes.Ldelem_I1);
906                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
907                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
908                                                 ilgen.Emit (OpCodes.Ldc_I4, 7);
909                                                 ilgen.Emit (OpCodes.And);
910                                                 ilgen.Emit (OpCodes.Shl);
911                                                 ilgen.Emit (OpCodes.And);
912                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
913                                                 ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, l1);
914                                         }
915                                         ilgen.MarkLabel (l_match);
916                                         if (!no_bump) {
917                                                 //  strpos++ / strpos--;
918                                                 ilgen.Emit (OpCodes.Ldarg_1);
919                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
920                                                 if (reverse)
921                                                         ilgen.Emit (OpCodes.Sub);
922                                                 else
923                                                         ilgen.Emit (OpCodes.Add);
924                                                 ilgen.Emit (OpCodes.Starg, 1);
925                                         }
926                                         //    continue;
927                                         ilgen.Emit (OpCodes.Br, l2);
928                                         //  }
929                                         //}
930                                         //return false;
931                                         ilgen.MarkLabel (l1);
932                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
933
934                                         ilgen.MarkLabel (l2);
935
936                                         pc += length;
937                                         break;
938                                 }
939                                 case RxOp.String:
940                                 case RxOp.UnicodeString: {
941                                         OpFlags flags = (OpFlags)op_flags [pc];
942                                         bool ignore = (flags & OpFlags.IgnoreCase) > 0;
943                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
944                                         bool unicode = (op == RxOp.UnicodeString);
945
946                                         if (unicode) {
947                                                 start = pc + 3;
948                                                 length = ReadShort (program, pc + 1);
949                                         } else {
950                                                 start = pc + 2;
951                                                 length = program [pc + 1];
952                                         }
953                                         //if (strpos + length > string_end)
954                                         //      return false;
955                                         if (reverse) {
956                                                 ilgen.Emit (OpCodes.Ldarg_1);
957                                                 ilgen.Emit (OpCodes.Ldc_I4, length);
958                                                 ilgen.Emit (OpCodes.Blt, frame.label_fail);
959                                         } else {
960                                                 ilgen.Emit (OpCodes.Ldarg_1);
961                                                 ilgen.Emit (OpCodes.Ldc_I4, length);
962                                                 ilgen.Emit (OpCodes.Add);
963                                                 ilgen.Emit (OpCodes.Ldarg_0);
964                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
965                                                 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
966                                         }
967
968                                         /* Avoid unsafe code in Moonlight build */
969 #if false && !NET_2_1
970                                         // FIXME:
971                                         if (reverse || unicode)
972                                                 throw new NotImplementedException ();
973                                         int i;
974                                         LocalBuilder local_strptr = ilgen.DeclareLocal (typeof (char).MakePointerType ());
975                                         // char *strptr = &str.start_char + strpos
976                                         ilgen.Emit (OpCodes.Ldarg_0);
977                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
978                                         ilgen.Emit (OpCodes.Ldflda, typeof (String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
979                                         ilgen.Emit (OpCodes.Ldarg_1);
980                                         ilgen.Emit (OpCodes.Ldc_I4_1);
981                                         ilgen.Emit (OpCodes.Shl);
982                                         ilgen.Emit (OpCodes.Add);
983                                         ilgen.Emit (OpCodes.Stloc, local_strptr);
984
985                                         end = start + length;
986                                         for (i = 0; i < length; ++i) {
987                                                 // if (*(strptr + i) != program [start + i])
988                                                 //   return false;
989                                                 if (ignore)
990                                                         ilgen.Emit (OpCodes.Ldloc, local_textinfo);
991                                                 ilgen.Emit (OpCodes.Ldloc, local_strptr);
992                                                 ilgen.Emit (OpCodes.Ldc_I4, i * 2);
993                                                 ilgen.Emit (OpCodes.Add);
994                                                 ilgen.Emit (OpCodes.Ldind_I2);
995                                                 if (ignore)
996                                                         ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
997                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)program [start + i]);
998                                                 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
999                                         }
1000
1001                                         // strpos += length
1002                                         ilgen.Emit (OpCodes.Ldarg_1);
1003                                         ilgen.Emit (OpCodes.Ldc_I4, length);
1004                                         ilgen.Emit (OpCodes.Add);
1005                                         ilgen.Emit (OpCodes.Starg, 1);
1006
1007 #else
1008                                         // Allocate a local for 'str' to save an indirection
1009                                         LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1010                                         ilgen.Emit (OpCodes.Ldarg_0);
1011                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
1012                                         ilgen.Emit (OpCodes.Stloc, local_str);
1013
1014                                         if (reverse) {
1015                                                 // strpos -= length;
1016                                                 ilgen.Emit (OpCodes.Ldarg_1);
1017                                                 ilgen.Emit (OpCodes.Ldc_I4, length);
1018                                                 ilgen.Emit (OpCodes.Sub);
1019                                                 ilgen.Emit (OpCodes.Starg, 1);
1020                                         }
1021
1022                                         // FIXME: Emit a loop for long strings
1023                                         end = start + (unicode ? length * 2 : length);
1024                                         while (start < end) {
1025                                                 //if (str [strpos] != program [start])
1026                                                 //      return false;
1027                                                 if (ignore)
1028                                                         ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1029                                                 ilgen.Emit (OpCodes.Ldloc, local_str);
1030                                                 ilgen.Emit (OpCodes.Ldarg_1);
1031                                                 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1032                                                 if (ignore)
1033                                                         ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1034                                                 ilgen.Emit (OpCodes.Ldc_I4, unicode ? ReadShort (program, start) : (int)program [start]);
1035                                                 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1036                                                 //strpos++;
1037                                                 ilgen.Emit (OpCodes.Ldarg_1);
1038                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1039                                                 ilgen.Emit (OpCodes.Add);
1040                                                 ilgen.Emit (OpCodes.Starg, 1);
1041
1042                                                 if (unicode)
1043                                                         start += 2;
1044                                                 else
1045                                                         start ++;
1046                                         }
1047
1048                                         if (reverse) {
1049                                                 // strpos -= length;
1050                                                 ilgen.Emit (OpCodes.Ldarg_1);
1051                                                 ilgen.Emit (OpCodes.Ldc_I4, length);
1052                                                 ilgen.Emit (OpCodes.Sub);
1053                                                 ilgen.Emit (OpCodes.Starg, 1);
1054                                         }
1055 #endif
1056
1057                                         pc = end;
1058                                         break;
1059                                 }
1060                                 case RxOp.OpenGroup: {
1061                                         //Open (program [pc + 1] | (program [pc + 2] << 8), strpos);
1062                                         int group_id = ReadShort (program, pc + 1);
1063                                         ilgen.Emit (OpCodes.Ldarg_0);
1064                                         ilgen.Emit (OpCodes.Ldc_I4, group_id);
1065                                         ilgen.Emit (OpCodes.Ldarg_1);
1066                                         ilgen.Emit (OpCodes.Call, GetMethod ("Open", ref mi_open));
1067
1068                                         pc += 3;
1069                                         break;
1070                                 }
1071                                 case RxOp.CloseGroup: {
1072                                         //Close (program [pc + 1] | (program [pc + 2] << 8), strpos);
1073                                         int group_id = ReadShort (program, pc + 1);
1074                                         ilgen.Emit (OpCodes.Ldarg_0);
1075                                         ilgen.Emit (OpCodes.Ldc_I4, group_id);
1076                                         ilgen.Emit (OpCodes.Ldarg_1);
1077                                         ilgen.Emit (OpCodes.Call, GetMethod ("Close", ref mi_close));
1078
1079                                         pc += 3;
1080                                         break;
1081                                 }
1082                                 case RxOp.Jump: {
1083                                         int target_pc = pc + ReadShort (program, pc + 1);
1084                                         if (target_pc > end_pc)
1085                                                 /* 
1086                                                  * This breaks the our code generation logic, see
1087                                                  * https://bugzilla.novell.com/show_bug.cgi?id=466151
1088                                                  * for an example.
1089                                                  */
1090                                                 return null;
1091                                         if (trace_compile)
1092                                                 Console.WriteLine ("\tjump target: {0}", target_pc);
1093                                         if (labels == null)
1094                                                 labels = new Dictionary <int, Label> ();
1095                                         Label l = CreateLabelForPC (ilgen, target_pc);
1096                                         ilgen.Emit (OpCodes.Br, l);
1097                                         pc += 3;
1098                                         break;
1099                                 }
1100                                 case RxOp.Test: {
1101                                         int target1 = pc + ReadShort (program, pc + 1);
1102                                         int target2 = pc + ReadShort (program, pc + 3);
1103
1104                                         if (trace_compile)
1105                                                 Console.WriteLine ("\temitting <test_expr>");
1106
1107                                         //  old_stros = strpos;
1108                                         LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1109                                         ilgen.Emit (OpCodes.Ldarg_1);
1110                                         ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1111
1112                                         Frame new_frame = new Frame (ilgen);
1113                                         m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 5, target1 < target2 ? target1 : target2, false, false, out pc);
1114                                         if (m == null)
1115                                                 return null;                                            
1116
1117                                         if (trace_compile) {
1118                                                 Console.WriteLine ("\temitted <test_expr>");
1119                                                 Console.WriteLine ("\ttarget1 = {0}", target1);
1120                                                 Console.WriteLine ("\ttarget2 = {0}", target2);
1121                                         }
1122
1123                                         Label l1 = CreateLabelForPC (ilgen, target1);
1124                                         Label l2 = CreateLabelForPC (ilgen, target2);
1125
1126                                         // Pass
1127                                         ilgen.MarkLabel (new_frame.label_pass);
1128                                         //  strpos = old_strpos;
1129                                         ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1130                                         ilgen.Emit (OpCodes.Starg, 1);
1131                                         ilgen.Emit (OpCodes.Br, l1);
1132                                                 
1133                                         // Fail
1134                                         ilgen.MarkLabel (new_frame.label_fail);
1135                                         //  strpos = old_strpos;
1136                                         ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1137                                         ilgen.Emit (OpCodes.Starg, 1);
1138                                         ilgen.Emit (OpCodes.Br, l2);
1139
1140                                         // Continue at pc, which should equal to target1
1141                                         break;
1142                                 }
1143                                 case RxOp.SubExpression: {
1144                                         int target = pc + ReadShort (program, pc + 1);
1145
1146                                         if (trace_compile)
1147                                                 Console.WriteLine ("\temitting <sub_expr>");
1148
1149                                         //  old_stros = strpos;
1150                                         LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1151                                         ilgen.Emit (OpCodes.Ldarg_1);
1152                                         ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1153
1154                                         Frame new_frame = new Frame (ilgen);
1155                                         m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target, false, false, out pc);
1156                                         if (m == null)
1157                                                 return null;                                            
1158
1159                                         if (trace_compile) {
1160                                                 Console.WriteLine ("\temitted <sub_expr>");
1161                                                 Console.WriteLine ("\ttarget = {0}", target);
1162                                         }
1163
1164                                         Label l1 = CreateLabelForPC (ilgen, target);
1165
1166                                         // Pass
1167                                         ilgen.MarkLabel (new_frame.label_pass);
1168                                         ilgen.Emit (OpCodes.Br, l1);
1169                                                 
1170                                         // Fail
1171                                         ilgen.MarkLabel (new_frame.label_fail);
1172                                         //  strpos = old_strpos;
1173                                         ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1174                                         ilgen.Emit (OpCodes.Starg, 1);
1175                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
1176
1177                                         // Continue at pc, which should equal to target
1178                                         break;
1179                                 }
1180                                 case RxOp.TestCharGroup: {
1181                                         int char_group_end = pc + ReadShort (program, pc + 1);
1182                                         pc += 3;
1183
1184                                         Label label_match = ilgen.DefineLabel ();
1185
1186                                         /* Determine the negate/reverse flags by examining the first op */
1187                                         OpFlags flags = (OpFlags)op_flags [pc];
1188
1189                                         /* Determine whenever this is a negated character class */
1190                                         /* If it is, then the conditions are ANDed together, not ORed */
1191                                         bool revert = (flags & OpFlags.Negate) > 0;
1192                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
1193
1194                                         /*
1195                                          * Generate code for all the matching ops in the group
1196                                          */
1197                                         while (pc < char_group_end) {
1198                                                 Frame new_frame = new Frame (ilgen);
1199                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, Int32.MaxValue, true, true, out pc);
1200                                                 if (m == null)
1201                                                         return null;                                            
1202
1203                                                 if (!revert) {
1204                                                         // Pass
1205                                                         ilgen.MarkLabel (new_frame.label_pass);
1206                                                         ilgen.Emit (OpCodes.Br, label_match);
1207                                                 
1208                                                         // Fail
1209                                                         // Just fall through to the next test
1210                                                         ilgen.MarkLabel (new_frame.label_fail);
1211                                                 } else {
1212                                                         // Pass
1213                                                         // Just fall through to the next test
1214                                                         ilgen.MarkLabel (new_frame.label_pass);
1215                                                         Label l2 = ilgen.DefineLabel ();
1216                                                         ilgen.Emit (OpCodes.Br, l2);
1217
1218                                                         // Fail
1219                                                         // Fail completely
1220                                                         ilgen.MarkLabel (new_frame.label_fail);
1221                                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
1222
1223                                                         ilgen.MarkLabel (l2);
1224                                                 }
1225                                         }
1226
1227                                         if (revert) {
1228                                                 /* Success */
1229                                                 ilgen.Emit (OpCodes.Br, label_match);
1230                                         } else {
1231                                                 // If we reached here, all the matching ops have failed
1232                                                 ilgen.Emit (OpCodes.Br, frame.label_fail);
1233                                         }
1234
1235                                         ilgen.MarkLabel (label_match);
1236
1237                                         //  strpos++ / strpos--;
1238                                         ilgen.Emit (OpCodes.Ldarg_1);
1239                                         ilgen.Emit (OpCodes.Ldc_I4_1);
1240                                         if (reverse)
1241                                                 ilgen.Emit (OpCodes.Sub);
1242                                         else
1243                                                 ilgen.Emit (OpCodes.Add);
1244                                         ilgen.Emit (OpCodes.Starg, 1);
1245
1246                                         break;
1247                                 }
1248                                 case RxOp.FastRepeat:
1249                                 case RxOp.FastRepeatLazy: {
1250                                         /*
1251                                          * A FastRepeat is a simplified version of Repeat which does
1252                                          * not contain another repeat inside, so backtracking is 
1253                                          * easier.
1254                                          * FIXME: Implement faster backtracking versions for
1255                                          * simple inner exceptions like chars/strings.
1256                                          */
1257                                         bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
1258                                         int tail = pc + ReadShort (program, pc + 1);
1259                                         start = ReadInt (program, pc + 3);
1260                                         end = ReadInt (program, pc + 7);
1261                                         //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
1262
1263                                         //  deep = null;
1264                                         ilgen.Emit (OpCodes.Ldarg_0);
1265                                         ilgen.Emit (OpCodes.Ldnull);
1266                                         ilgen.Emit (OpCodes.Stfld, fi_deep);
1267
1268                                         LocalBuilder local_length = ilgen.DeclareLocal (typeof (int));
1269
1270                                         ilgen.Emit (OpCodes.Ldc_I4_0);
1271                                         ilgen.Emit (OpCodes.Stloc, local_length);
1272
1273                                         LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1274                                         
1275                                         // First match at least 'start' items
1276                                         if (start > 0) {
1277                                                 //for (length = 0; length < start; ++length) {
1278                                                 Label l_loop_footer = ilgen.DefineLabel ();
1279                                                 ilgen.Emit (OpCodes.Br, l_loop_footer);
1280                                                 Label l_loop_body = ilgen.DefineLabel ();
1281                                                 ilgen.MarkLabel (l_loop_body);
1282
1283                                                 // int old_strpos = strpos;
1284                                                 ilgen.Emit (OpCodes.Ldarg_1);
1285                                                 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1286                                                 
1287                                                 // if (!EvalByteCode (pc + 11, strpos, ref res))
1288                                                 Frame new_frame = new Frame (ilgen);
1289                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1290                                                 if (m == null)
1291                                                         return null;
1292
1293                                                 // Fail
1294                                                 // return false;
1295                                                 ilgen.MarkLabel (new_frame.label_fail);
1296                                                 ilgen.Emit (OpCodes.Br, frame.label_fail);
1297
1298                                                 // Pass
1299                                                 ilgen.MarkLabel (new_frame.label_pass);
1300                                                 // length++
1301                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1302                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1303                                                 ilgen.Emit (OpCodes.Add);
1304                                                 ilgen.Emit (OpCodes.Stloc, local_length);
1305                                                 // Loop footer
1306                                                 ilgen.MarkLabel (l_loop_footer);
1307                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1308                                                 ilgen.Emit (OpCodes.Ldc_I4, start);
1309                                                 ilgen.Emit (OpCodes.Blt, l_loop_body);
1310                                         }
1311
1312                                         if (lazy) {
1313                                                 Label l_loop_footer = ilgen.DefineLabel ();
1314                                                 //while (true) {
1315                                                 ilgen.Emit (OpCodes.Br, l_loop_footer);
1316                                                 Label l_loop_body = ilgen.DefineLabel ();
1317                                                 ilgen.MarkLabel (l_loop_body);
1318                                                 // Match the tail
1319                                                 //  int cp = Checkpoint ();
1320                                                 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1321                                                 ilgen.Emit (OpCodes.Ldarg_0);
1322                                                 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1323                                                 ilgen.Emit (OpCodes.Stloc, local_cp);
1324
1325                                                 // int old_strpos = strpos;
1326                                                 ilgen.Emit (OpCodes.Ldarg_1);
1327                                                 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1328
1329                                                 //  if (EvalByteCode (tail, strpos, ref res)) {
1330                                                 Frame new_frame = new Frame (ilgen);
1331                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1332                                                 if (m == null)
1333                                                         return null;
1334
1335                                                 // Success:
1336                                                 ilgen.MarkLabel (new_frame.label_pass);
1337                                                 //    return true;
1338                                                 ilgen.Emit (OpCodes.Br, frame.label_pass);
1339
1340                                                 // Fail:
1341                                                 ilgen.MarkLabel (new_frame.label_fail);
1342                                                 //  Backtrack (cp);
1343                                                 ilgen.Emit (OpCodes.Ldarg_0);
1344                                                 ilgen.Emit (OpCodes.Ldloc, local_cp);
1345                                                 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1346                                                 // strpos = old_strpos;
1347                                                 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1348                                                 ilgen.Emit (OpCodes.Starg, 1);
1349
1350                                                 //if (length >= end)
1351                                                 //  return false;
1352                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1353                                                 ilgen.Emit (OpCodes.Ldc_I4, end);
1354                                                 ilgen.Emit (OpCodes.Bge, frame.label_fail);
1355
1356                                                 // Match an item
1357                                                 //if (!EvalByteCode (pc + 11, strpos, ref res))
1358                                                 new_frame = new Frame (ilgen);
1359                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1360                                                 if (m == null)
1361                                                         return null;
1362
1363                                                 // Success:
1364                                                 ilgen.MarkLabel (new_frame.label_pass);
1365                                                 // length ++;
1366                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1367                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1368                                                 ilgen.Emit (OpCodes.Add);
1369                                                 ilgen.Emit (OpCodes.Stloc, local_length);
1370                                                 ilgen.Emit (OpCodes.Br, l_loop_body);
1371                                                 
1372                                                 // Fail:
1373                                                 ilgen.MarkLabel (new_frame.label_fail);
1374                                                 // return false;
1375                                                 ilgen.Emit (OpCodes.Br, frame.label_fail);
1376
1377                                                 // Loop footer
1378                                                 ilgen.MarkLabel (l_loop_footer);
1379                                                 ilgen.Emit (OpCodes.Br, l_loop_body);
1380                                         } else {
1381                                                 // Then match as many items as possible, recording
1382                                                 // backtracking information
1383                                                 
1384                                                 //int old_stack_size = stack.Count;
1385                                                 LocalBuilder local_old_stack_size = ilgen.DeclareLocal (typeof (int));
1386                                                 ilgen.Emit (OpCodes.Ldarg_0);
1387                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1388                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1389                                                 ilgen.Emit (OpCodes.Stloc, local_old_stack_size);
1390                                                 //while (length < end) {
1391                                                 Label l_loop_footer = ilgen.DefineLabel ();
1392                                                 ilgen.Emit (OpCodes.Br, l_loop_footer);
1393                                                 Label l_loop_body = ilgen.DefineLabel ();
1394                                                 ilgen.MarkLabel (l_loop_body);
1395                                                 //  int cp = Checkpoint ();
1396                                                 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1397                                                 ilgen.Emit (OpCodes.Ldarg_0);
1398                                                 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1399                                                 ilgen.Emit (OpCodes.Stloc, local_cp);
1400
1401                                                 // int old_strpos = strpos;
1402                                                 ilgen.Emit (OpCodes.Ldarg_1);
1403                                                 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1404
1405                                                 //  if (!EvalByteCode (pc + 11, strpos, ref res)) {
1406                                                 Frame new_frame = new Frame (ilgen);
1407                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1408                                                 if (m == null)
1409                                                         return null;
1410
1411                                                 // Fail:
1412                                                 ilgen.MarkLabel (new_frame.label_fail);
1413                                                 // strpos = old_strpos
1414                                                 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1415                                                 ilgen.Emit (OpCodes.Starg, 1);
1416                                                 //    Backtrack (cp);
1417                                                 ilgen.Emit (OpCodes.Ldarg_0);
1418                                                 ilgen.Emit (OpCodes.Ldloc, local_cp);
1419                                                 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1420
1421                                                 //    break;
1422                                                 Label l_after_loop = ilgen.DefineLabel ();
1423                                                 ilgen.Emit (OpCodes.Br, l_after_loop);
1424
1425                                                 // Success:
1426                                                 ilgen.MarkLabel (new_frame.label_pass);
1427
1428                                                 //stack.Push (cp);
1429                                                 ilgen.Emit (OpCodes.Ldarg_0);
1430                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1431                                                 ilgen.Emit (OpCodes.Ldloc, local_cp);
1432                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1433                                                 //stack.Push (strpos);
1434                                                 ilgen.Emit (OpCodes.Ldarg_0);
1435                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1436                                                 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1437                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1438                                                 // length++
1439                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1440                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1441                                                 ilgen.Emit (OpCodes.Add);
1442                                                 ilgen.Emit (OpCodes.Stloc, local_length);
1443                                                 // Loop footer
1444                                                 ilgen.MarkLabel (l_loop_footer);
1445                                                 ilgen.Emit (OpCodes.Ldloc, local_length);
1446                                                 ilgen.Emit (OpCodes.Ldc_I4, end);
1447                                                 ilgen.Emit (OpCodes.Blt, l_loop_body);
1448
1449                                                 ilgen.MarkLabel (l_after_loop);
1450
1451                                                 // Then, match the tail, backtracking as necessary.
1452
1453                                                 //while (true) {
1454                                                 l_loop_footer = ilgen.DefineLabel ();
1455                                                 ilgen.Emit (OpCodes.Br, l_loop_footer);
1456                                                 l_loop_body = ilgen.DefineLabel ();
1457                                                 ilgen.MarkLabel (l_loop_body);
1458
1459                                                 if (RxInterpreter.trace_rx) {
1460                                                         ilgen.Emit (OpCodes.Ldstr, "matching tail at: {0}");
1461                                                         ilgen.Emit (OpCodes.Ldarg_1);
1462                                                         ilgen.Emit (OpCodes.Box, typeof (int));
1463                                                         ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1464                                                 }
1465
1466                                                 //  if (EvalByteCode (tail, strpos, ref res)) {
1467                                                 new_frame = new Frame (ilgen);
1468                                                 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1469                                                 if (m == null)
1470                                                         return null;
1471
1472                                                 // Success:
1473                                                 ilgen.MarkLabel (new_frame.label_pass);
1474
1475                                                 if (RxInterpreter.trace_rx) {
1476                                                         ilgen.Emit (OpCodes.Ldstr, "tail matched at: {0}");
1477                                                         ilgen.Emit (OpCodes.Ldarg_1);
1478                                                         ilgen.Emit (OpCodes.Box, typeof (int));
1479                                                         ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1480                                                 }
1481
1482                                                 //      stack.Count = old_stack_size;
1483                                                 ilgen.Emit (OpCodes.Ldarg_0);
1484                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1485                                                 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1486                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "set_Count", ref mi_stack_set_count));
1487                                                 //  return true;
1488                                                 ilgen.Emit (OpCodes.Br, frame.label_pass);
1489
1490                                                 // Fail:
1491                                                 ilgen.MarkLabel (new_frame.label_fail);
1492
1493                                                 if (RxInterpreter.trace_rx) {
1494                                                         ilgen.Emit (OpCodes.Ldstr, "tail failed to match at: {0}");
1495                                                         ilgen.Emit (OpCodes.Ldarg_1);
1496                                                         ilgen.Emit (OpCodes.Box, typeof (int));
1497                                                         ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1498                                                 }
1499
1500                                                 //  if (stack.Count == old_stack_size)
1501                                                 //              return false;
1502                                                 ilgen.Emit (OpCodes.Ldarg_0);
1503                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1504                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1505                                                 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1506                                                 ilgen.Emit (OpCodes.Beq, frame.label_fail);
1507                                                 
1508                                                 // Backtrack
1509                                                 //strpos = stack.Pop ();
1510                                                 ilgen.Emit (OpCodes.Ldarg_0);
1511                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1512                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1513                                                 ilgen.Emit (OpCodes.Starg, 1);
1514                                                 //Backtrack (stack.Pop ());
1515                                                 ilgen.Emit (OpCodes.Ldarg_0);
1516                                                 ilgen.Emit (OpCodes.Ldarg_0);
1517                                                 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1518                                                 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1519                                                 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1520
1521                                                 if (RxInterpreter.trace_rx) {
1522                                                         //Console.WriteLine ("backtracking to: {0}", strpos);
1523                                                         ilgen.Emit (OpCodes.Ldstr, "backtracking to: {0}");
1524                                                         ilgen.Emit (OpCodes.Ldarg_1);
1525                                                         ilgen.Emit (OpCodes.Box, typeof (int));
1526                                                         ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1527                                                 }
1528
1529                                                 // Loop footer
1530                                                 ilgen.MarkLabel (l_loop_footer);
1531                                                 ilgen.Emit (OpCodes.Br, l_loop_body);
1532                                         }
1533
1534                                         // We already processed the tail
1535                                         pc = out_pc;
1536                                         goto End;
1537                                 }
1538
1539                                 case RxOp.CategoryAny:
1540                                 case RxOp.CategoryAnySingleline:
1541                                 case RxOp.CategoryWord:
1542                                 case RxOp.CategoryDigit:
1543                                 case RxOp.CategoryWhiteSpace:
1544                                 case RxOp.CategoryEcmaWord:
1545                                 case RxOp.CategoryEcmaWhiteSpace:
1546                                 case RxOp.CategoryUnicodeSpecials:
1547                                 case RxOp.CategoryUnicode: {
1548                                         OpFlags flags = (OpFlags)op_flags [pc];
1549                                         bool negate = (flags & OpFlags.Negate) > 0;
1550                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
1551
1552                                         //if (strpos < string_end) {
1553                                         Label l_nomatch = ilgen.DefineLabel ();
1554                                         if (reverse) {
1555                                                 ilgen.Emit (OpCodes.Ldarg_1);
1556                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
1557                                                 ilgen.Emit (OpCodes.Ble, l_nomatch);
1558                                         } else {
1559                                                 ilgen.Emit (OpCodes.Ldarg_1);
1560                                                 ilgen.Emit (OpCodes.Ldarg_0);
1561                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1562                                                 ilgen.Emit (OpCodes.Bge, l_nomatch);
1563                                         }
1564
1565                                         //  int c = str [strpos];
1566                                         LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
1567                                         ilgen.Emit (OpCodes.Ldarg_0);
1568                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
1569                                         ilgen.Emit (OpCodes.Ldarg_1);
1570                                         if (reverse) {
1571                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1572                                                 ilgen.Emit (OpCodes.Sub);
1573                                         }
1574                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1575                                         ilgen.Emit (OpCodes.Stloc, local_c);
1576
1577                                         Label l_match = ilgen.DefineLabel ();
1578
1579                                         Label l_true, l_false;
1580
1581                                         l_true = negate ? l_nomatch : l_match;
1582                                         l_false = negate ? l_match : l_nomatch;
1583
1584                                         switch (op) {
1585                                         case RxOp.CategoryAny:
1586                                                 // if (str [strpos] != '\n') {
1587                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1588                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1589                                                 ilgen.Emit (OpCodes.Bne_Un, l_true);
1590                                                 break;
1591                                         case RxOp.CategoryAnySingleline:
1592                                                 ilgen.Emit (OpCodes.Br, l_true);
1593                                                 break;
1594                                         case RxOp.CategoryWord:
1595                                                 //  if (Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation) {
1596                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1597                                                 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsLetterOrDigit", new Type [] { typeof (char) }));
1598                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1599                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1600                                                 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1601                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)UnicodeCategory.ConnectorPunctuation);
1602                                                 ilgen.Emit (OpCodes.Beq, l_true);
1603                                                 break;
1604                                         case RxOp.CategoryDigit:
1605                                                 // if (Char.IsDigit (c)) {
1606                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1607                                                 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsDigit", new Type [] { typeof (char) }));
1608                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1609                                                 break;
1610                                         case RxOp.CategoryWhiteSpace:
1611                                                 // if (Char.IsWhiteSpace (c)) {
1612                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1613                                                 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsWhiteSpace", new Type [] { typeof (char) }));
1614                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1615                                                 break;
1616                                         case RxOp.CategoryEcmaWord:
1617                                                 // if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_') {
1618                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1619                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'a' - 1);
1620                                                 ilgen.Emit (OpCodes.Cgt);
1621                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1622                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'z' + 1);
1623                                                 ilgen.Emit (OpCodes.Clt);
1624                                                 ilgen.Emit (OpCodes.And);
1625                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1626
1627                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1628                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'A' - 1);
1629                                                 ilgen.Emit (OpCodes.Cgt);
1630                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1631                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'Z' + 1);
1632                                                 ilgen.Emit (OpCodes.Clt);
1633                                                 ilgen.Emit (OpCodes.And);
1634                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1635
1636                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1637                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'0' - 1);
1638                                                 ilgen.Emit (OpCodes.Cgt);
1639                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1640                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'9' + 1);
1641                                                 ilgen.Emit (OpCodes.Clt);
1642                                                 ilgen.Emit (OpCodes.And);
1643                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1644
1645                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1646                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'_');
1647                                                 ilgen.Emit (OpCodes.Beq, l_true);
1648                                                 break;
1649                                         case RxOp.CategoryEcmaWhiteSpace:
1650                                                 // if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') {
1651                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1652                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)' ');
1653                                                 ilgen.Emit (OpCodes.Beq, l_true);
1654                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1655                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\t');
1656                                                 ilgen.Emit (OpCodes.Beq, l_true);
1657                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1658                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1659                                                 ilgen.Emit (OpCodes.Beq, l_true);
1660                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1661                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\r');
1662                                                 ilgen.Emit (OpCodes.Beq, l_true);
1663                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1664                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\f');
1665                                                 ilgen.Emit (OpCodes.Beq, l_true);
1666                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1667                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\v');
1668                                                 ilgen.Emit (OpCodes.Beq, l_true);
1669                                                 break;
1670                                         case RxOp.CategoryUnicodeSpecials:
1671                                                 // if ('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD') {
1672                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1673                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' - 1);
1674                                                 ilgen.Emit (OpCodes.Cgt);
1675                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1676                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' + 1);
1677                                                 ilgen.Emit (OpCodes.Clt);
1678                                                 ilgen.Emit (OpCodes.And);
1679                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1680
1681                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1682                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFF0' - 1);
1683                                                 ilgen.Emit (OpCodes.Cgt);
1684                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1685                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFFD' + 1);
1686                                                 ilgen.Emit (OpCodes.Clt);
1687                                                 ilgen.Emit (OpCodes.And);
1688                                                 ilgen.Emit (OpCodes.Brtrue, l_true);
1689                                                 break;
1690                                         case RxOp.CategoryUnicode:
1691                                                 // if (Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]) {                                              
1692                                                 ilgen.Emit (OpCodes.Ldloc, local_c);
1693                                                 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1694                                                 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
1695                                                 ilgen.Emit (OpCodes.Beq, l_true);
1696                                                 break;
1697                                         }
1698
1699                                         ilgen.Emit (OpCodes.Br, l_false);
1700
1701                                         ilgen.MarkLabel (l_match);
1702
1703                                         //    strpos++;
1704                                         if (!no_bump) {
1705                                                 ilgen.Emit (OpCodes.Ldarg_1);
1706                                                 ilgen.Emit (OpCodes.Ldc_I4_1);
1707                                                 if (reverse)
1708                                                         ilgen.Emit (OpCodes.Sub);
1709                                                 else
1710                                                         ilgen.Emit (OpCodes.Add);
1711                                                 ilgen.Emit (OpCodes.Starg, 1);
1712                                         }
1713                                         //  }
1714                                         Label l2 = ilgen.DefineLabel ();
1715                                         ilgen.Emit (OpCodes.Br, l2);
1716                                         //}
1717                                         ilgen.MarkLabel (l_nomatch);
1718                                         //return false;
1719                                         ilgen.Emit (OpCodes.Br, frame.label_fail);
1720
1721                                         ilgen.MarkLabel (l2);
1722
1723                                         if (op == RxOp.CategoryUnicode)
1724                                                 pc += 2;
1725                                         else
1726                                                 pc++;
1727                                         break;
1728                                 }
1729                                 case RxOp.Reference: {
1730                                         OpFlags flags = (OpFlags)op_flags [pc];
1731                                         bool ignore = (flags & OpFlags.IgnoreCase) > 0;
1732                                         bool reverse = (flags & OpFlags.RightToLeft) > 0;
1733
1734                                         //length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
1735                                         LocalBuilder loc_length = ilgen.DeclareLocal (typeof (int));
1736                                         ilgen.Emit (OpCodes.Ldarg_0);
1737                                         ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1)); 
1738                                         ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "GetLastDefined", ref mi_get_last_defined));                                       
1739                                         ilgen.Emit (OpCodes.Stloc, loc_length);
1740                                         //if (length < 0)
1741                                         //  return false;
1742                                         ilgen.Emit (OpCodes.Ldloc, loc_length);
1743                                         ilgen.Emit (OpCodes.Ldc_I4_0);
1744                                         ilgen.Emit (OpCodes.Blt, frame.label_fail);
1745                                         //start = marks [length].Index;
1746                                         LocalBuilder loc_start = ilgen.DeclareLocal (typeof (int));
1747                                         ilgen.Emit (OpCodes.Ldarg_0);
1748                                         ilgen.Emit (OpCodes.Ldfld, fi_marks);
1749                                         ilgen.Emit (OpCodes.Ldloc, loc_length);
1750                                         ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1751                                         ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Index", ref mi_mark_get_index));
1752                                         ilgen.Emit (OpCodes.Stloc, loc_start);
1753                                         // length = marks [length].Length;
1754                                         ilgen.Emit (OpCodes.Ldarg_0);
1755                                         ilgen.Emit (OpCodes.Ldfld, fi_marks);
1756                                         ilgen.Emit (OpCodes.Ldloc, loc_length);
1757                                         ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1758                                         ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Length", ref mi_mark_get_length));
1759                                         ilgen.Emit (OpCodes.Stloc, loc_length);
1760                                         if (reverse) {
1761                                                 //ptr -= length;
1762                                                 ilgen.Emit (OpCodes.Ldarg_1);
1763                                                 ilgen.Emit (OpCodes.Ldloc, loc_length);
1764                                                 ilgen.Emit (OpCodes.Sub);
1765                                                 ilgen.Emit (OpCodes.Starg, 1);
1766                                                 //if (ptr < 0)
1767                                                 //goto Fail;
1768                                                 ilgen.Emit (OpCodes.Ldarg_1);
1769                                                 ilgen.Emit (OpCodes.Ldc_I4_0);
1770                                                 ilgen.Emit (OpCodes.Blt, frame.label_fail);
1771                                         } else {
1772                                                 //if (strpos + length > string_end)
1773                                                 //  return false;
1774                                                 ilgen.Emit (OpCodes.Ldarg_1);
1775                                                 ilgen.Emit (OpCodes.Ldloc, loc_length);
1776                                                 ilgen.Emit (OpCodes.Add);
1777                                                 ilgen.Emit (OpCodes.Ldarg_0);
1778                                                 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1779                                                 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
1780                                         }
1781
1782                                         LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1783                                         ilgen.Emit (OpCodes.Ldarg_0);
1784                                         ilgen.Emit (OpCodes.Ldfld, fi_str);
1785                                         ilgen.Emit (OpCodes.Stloc, local_str);
1786
1787                                         // end = start + length;
1788                                         LocalBuilder loc_end = ilgen.DeclareLocal (typeof (int));
1789                                         ilgen.Emit (OpCodes.Ldloc, loc_start);
1790                                         ilgen.Emit (OpCodes.Ldloc, loc_length);
1791                                         ilgen.Emit (OpCodes.Add);
1792                                         ilgen.Emit (OpCodes.Stloc, loc_end);
1793                                         //for (; start < end; ++start) {
1794                                         Label l_loop_footer = ilgen.DefineLabel ();
1795                                         ilgen.Emit (OpCodes.Br, l_loop_footer);
1796                                         Label l_loop_body = ilgen.DefineLabel ();
1797                                         ilgen.MarkLabel (l_loop_body);
1798                                         //if (str [strpos] != str [start])
1799                                         //return false;
1800                                         if (ignore)
1801                                                 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1802                                         ilgen.Emit (OpCodes.Ldloc, local_str);
1803                                         ilgen.Emit (OpCodes.Ldarg_1);
1804                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1805                                         if (ignore)
1806                                                 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1807                                         if (ignore)
1808                                                 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1809                                         ilgen.Emit (OpCodes.Ldloc, local_str);
1810                                         ilgen.Emit (OpCodes.Ldloc, loc_start);
1811                                         ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1812                                         if (ignore)
1813                                                 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1814                                         ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1815                                         // strpos++;
1816                                         ilgen.Emit (OpCodes.Ldarg_1);
1817                                         ilgen.Emit (OpCodes.Ldc_I4_1);
1818                                         ilgen.Emit (OpCodes.Add);
1819                                         ilgen.Emit (OpCodes.Starg, 1);
1820                                         // start++
1821                                         ilgen.Emit (OpCodes.Ldloc, loc_start);
1822                                         ilgen.Emit (OpCodes.Ldc_I4_1);
1823                                         ilgen.Emit (OpCodes.Add);
1824                                         ilgen.Emit (OpCodes.Stloc, loc_start);
1825                                         // Loop footer
1826                                         ilgen.MarkLabel (l_loop_footer);
1827                                         ilgen.Emit (OpCodes.Ldloc, loc_start);
1828                                         ilgen.Emit (OpCodes.Ldloc, loc_end);
1829                                         ilgen.Emit (OpCodes.Blt, l_loop_body);
1830
1831                                         if (reverse) {
1832                                                 //ptr -= length;
1833                                                 ilgen.Emit (OpCodes.Ldarg_1);
1834                                                 ilgen.Emit (OpCodes.Ldloc, loc_length);
1835                                                 ilgen.Emit (OpCodes.Sub);
1836                                                 ilgen.Emit (OpCodes.Starg, 1);
1837                                         }
1838
1839                                         pc += 3;
1840                                         break;
1841                                 }
1842                                 case RxOp.Repeat:
1843                                 case RxOp.RepeatLazy:
1844                                 case RxOp.IfDefined:
1845                                         // FIXME:
1846                                         if (RxInterpreter.trace_rx || trace_compile)
1847                                                 Console.WriteLine ("Opcode " + op + " not supported.");
1848                                         return null;
1849                                 default:
1850                                         throw new NotImplementedException ("Opcode '" + op + "' not supported by the regex->IL compiler.");
1851                             }
1852
1853                                 if (one_op)
1854                                         break;
1855                         }
1856
1857                         End:
1858
1859                         out_pc = pc;
1860
1861                         return m;
1862                 }
1863         }
1864 #else
1865         class CILCompiler : RxCompiler {
1866         }
1867 #endif
1868
1869 }
1870