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