Author: zoltan
Date: 2008-02-13 09:30:06 -0500 (Wed, 13 Feb 2008)
New Revision: 95580

Modified:
   trunk/mcs/class/System/System.Text.RegularExpressions/ChangeLog
   trunk/mcs/class/System/System.Text.RegularExpressions/RxCompiler.cs
   trunk/mcs/class/System/System.Text.RegularExpressions/RxInterpreter.cs
Log:
2008-02-13  Zoltan Varga  <[EMAIL PROTECTED]>

        * RxInterpreter.cs RxCompiler.cs: First version of regex IL compiler.


Modified: trunk/mcs/class/System/System.Text.RegularExpressions/ChangeLog
===================================================================
--- trunk/mcs/class/System/System.Text.RegularExpressions/ChangeLog     
2008-02-13 14:29:49 UTC (rev 95579)
+++ trunk/mcs/class/System/System.Text.RegularExpressions/ChangeLog     
2008-02-13 14:30:06 UTC (rev 95580)
@@ -1,4 +1,7 @@
+2008-02-13  Zoltan Varga  <[EMAIL PROTECTED]>
 
+       * RxInterpreter.cs RxCompiler.cs: First version of regex IL compiler.
+
 Wed Feb 13 13:18:12 CET 2008 Paolo Molaro <[EMAIL PROTECTED]>
 
        * RxCompiler.cs, RxInterpreter.cs, RxOp.cs: unicode categories and

Modified: trunk/mcs/class/System/System.Text.RegularExpressions/RxCompiler.cs
===================================================================
--- trunk/mcs/class/System/System.Text.RegularExpressions/RxCompiler.cs 
2008-02-13 14:29:49 UTC (rev 95579)
+++ trunk/mcs/class/System/System.Text.RegularExpressions/RxCompiler.cs 
2008-02-13 14:30:06 UTC (rev 95580)
@@ -1,6 +1,8 @@
 using System;
 using System.Collections;
 using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
 
 namespace System.Text.RegularExpressions {
 
@@ -39,8 +41,8 @@
        }
 
        class RxCompiler : ICompiler {
-               byte[] program = new byte [32];
-               int curpos = 0;
+               protected byte[] program = new byte [32];
+               protected int curpos = 0;
 
                public RxCompiler () {
                }
@@ -109,7 +111,7 @@
                        Buffer.BlockCopy (program, 0, code, 0, curpos);
                        //Console.WriteLine ("Program size: {0}", curpos);
 
-                       return new RxInterpreterFactory (code);
+                       return new RxInterpreterFactory (code, null);
                }
 
                public void EmitFalse ()
@@ -686,13 +688,507 @@
 
        }
 
+       //
+       // Compiler which generates IL bytecode to perform the matching instead 
of
+       // interpreting a program.
+       // For simplicity, we inherit from RxCompiler, and generate the IL code 
based
+       // on the program generated by it. This also allows us to fallback to 
interpretation
+       // if we can't handle something.
+       // This is net 2.0, since 1.0 doesn't support DynamicMethods
+       // FIXME: Add support for 1.0, and CompileToAssembly
+       // FIXME: Emit one method with a switch instead of many methods
+       // FIXME: Avoid ref ptr, since it is bad for register allocation
+       //
+
+#if NET_2_0
+       class CILCompiler : RxCompiler, ICompiler {
+               DynamicMethod[] eval_methods;
+               bool[] eval_methods_defined;
+
+               IMachineFactory ICompiler.GetMachineFactory () {
+                       byte[] code = new byte [curpos];
+                       Buffer.BlockCopy (program, 0, code, 0, curpos);
+
+                       eval_methods = new DynamicMethod [code.Length];
+                       eval_methods_defined = new bool [code.Length];
+
+                       // The main eval method
+                   DynamicMethod main = GetEvalMethod (code, 11);
+                       if (main != null)
+                               return new RxInterpreterFactory (code, 
(EvalDelegate)main.CreateDelegate (typeof (EvalDelegate)));
+                       else
+                               return new RxInterpreterFactory (code, null);
+               }
+
+               DynamicMethod GetEvalMethod (byte[] program, int pc) {
+                       if (eval_methods_defined [pc])
+                               return eval_methods [pc];
+
+                       // FIXME: Recursion ?
+                       eval_methods_defined [pc] = true;
+
+                       eval_methods [pc] = CreateEvalMethod (program, pc);
+                       return eval_methods [pc];
+               }
+
+               private FieldInfo GetInterpreterField (string name) {
+                       return typeof (RxInterpreter).GetField (name, 
BindingFlags.Instance|BindingFlags.NonPublic);
+               }
+
+               private MethodInfo GetInterpreterMethod (string name) {
+                       return typeof (RxInterpreter).GetMethod (name, 
BindingFlags.Instance|BindingFlags.NonPublic);
+               }
+
+               private string GetString (ushort[] program, int pc) {
+                       int len = program[pc + 1];
+                       int str = pc + 2;
+
+                       char[] cs = new char[len];
+                       for (int i = 0; i < len; ++ i)
+                               cs[i] = (char)program[str ++];
+
+                       return new string (cs);
+               }
+
+               private int ReadInt (byte[] code, int pc)
+               {
+                       int val = code [pc];
+                       val |= code [pc + 1] << 8;
+                       val |= code [pc + 2] << 16;
+                       val |= code [pc + 3] << 24;
+                       return val;
+               }
+
+               private MethodInfo GetEvalMethodWithFallback (byte[] program, 
int pc, out bool fallback) {
+                       DynamicMethod eval = GetEvalMethod (program, pc);
+                       fallback = eval != null;
+                       if (eval != null) {
+                               fallback = false;
+                               return eval;
+                       } else {
+                               fallback = true;
+                               return GetInterpreterMethod ("EvalByteCode");
+                       }
+               }
+
+               //
+               // Create a dynamic method which is the Interpreter.Eval method 
specialized
+               // to the given program and a given pc.
+               // Keep this in synch with Interpreter.Eval ()
+               //
+               DynamicMethod CreateEvalMethod (byte[] program, int pc) {
+                       DynamicMethod m = new DynamicMethod ("Eval_" + pc, 
typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof 
(int).MakeByRefType () }, typeof (RxInterpreter), true);
+                       ILGenerator ilgen = m.GetILGenerator ();
+
+                       /* 
+                          Args:
+                          interp - 0
+                          strpos - 1
+                          strpos_result - 2
+                       */
+
+                       int start, length, end;
+                       bool fallback;
+
+                       Label label_fail = ilgen.DefineLabel ();
+
+                       while (true) {
+                               RxOp op = (RxOp)program [pc];
+
+                               switch (op) {
+                               case RxOp.Anchor: {
+                                       length = program [pc + 3] | (program 
[pc + 4] << 8);
+                                       pc += program [pc + 1] | (program [pc + 
2] << 8);
+
+                                       // FIXME: Group support
+                                       
+                                       // Optimize some common cases by 
inlining the code generated for the
+                                       // anchor body 
+                                       RxOp anch_op = (RxOp)program [pc];
+                                       // FIXME: Do this even if the archor op 
is not the last in the regex
+                                       if (anch_op == RxOp.Char && 
(RxOp)program [pc + 2] == RxOp.True) {
+
+                                               /*
+                                                * while (strpos < string_end) {
+                                                *   if (str [strpos] == 
program [pc + 1]) {
+                                                *     match_start = strpos;
+                                                *     strpos_result = strpos + 
1;
+                                                *     return true;
+                                                *   }
+                                                *   strpos ++;
+                                                * }
+                                                * return false;
+                                                */
+                                               // Add some locals to avoid an 
indirection
+                                               LocalBuilder local_string_end = 
ilgen.DeclareLocal (typeof (int));
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("string_end"));
+                                               ilgen.Emit (OpCodes.Stloc, 
local_string_end);
+                                               LocalBuilder local_str = 
ilgen.DeclareLocal (typeof (string));
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("str"));
+                                               ilgen.Emit (OpCodes.Stloc, 
local_str);
+
+                                               //while (strpos < string_end) {
+                                               // -> Done at the end of the 
loop like mcs does
+                                               Label l1 = ilgen.DefineLabel ();
+                                               Label l2 = ilgen.DefineLabel ();
+                                               ilgen.Emit (OpCodes.Br, l2);
+                                               ilgen.MarkLabel (l1);
+
+                                               //  if (str [strpos] == program 
[pc + 1]) {
+                                               Label l3 = ilgen.DefineLabel ();
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_str);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Callvirt, 
typeof (string).GetMethod ("get_Chars"));
+                                               ilgen.Emit (OpCodes.Conv_I4);
+                                               ilgen.Emit (OpCodes.Ldc_I4, 
(int)program [pc + 1]);
+                                               ilgen.Emit (OpCodes.Bne_Un, l3);
+
+                                               //    match_start = strpos;
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Stfld, 
GetInterpreterField ("match_start"));
+                                               //    strpos_result = strpos + 
1;
+                                               ilgen.Emit (OpCodes.Ldarg_2);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Stind_I4);
+                                               //    return true;
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Ret);
+                                               //  }
+                                               ilgen.MarkLabel (l3);
+                                               //  strpos++;
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Starg, 1);
+                                               //}
+                                               ilgen.MarkLabel (l2);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_string_end);
+                                               ilgen.Emit (OpCodes.Blt, l1);
+
+                                               //return false;
+                                               ilgen.Emit (OpCodes.Br, 
label_fail);
+                                       } else {
+                                               // General case
+
+                                               //Console.WriteLine ("Anchor op 
" + anch_op);
+
+                                               //while (strpos < string_end) {
+                                               Label l1 = ilgen.DefineLabel ();
+                                               Label l2 = ilgen.DefineLabel ();
+                                               ilgen.MarkLabel (l1);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("string_end"));
+                                               ilgen.Emit (OpCodes.Bge, l2);
+                                               //  int res = strpos;
+                                               LocalBuilder local_res = 
ilgen.DeclareLocal (typeof (int));
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Stloc, 
local_res);
+                                               //  if (EvalByteCode (pc, 
strpos, ref res)) {
+                                               Label l3 = ilgen.DefineLabel ();
+                                               MethodInfo eval = 
GetEvalMethodWithFallback (program, pc, out fallback);
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               if (fallback)
+                                                       ilgen.Emit 
(OpCodes.Ldc_I4, pc);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldloca, 
local_res);
+                                               ilgen.Emit (OpCodes.Call, eval);
+                                               ilgen.Emit (OpCodes.Brfalse, 
l3);
+                                               //    match_start = strpos;
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Stfld, 
GetInterpreterField ("match_start"));
+                                               //    strpos_result = res;
+                                               ilgen.Emit (OpCodes.Ldarg_2);
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_res);
+                                               ilgen.Emit (OpCodes.Stind_I4);
+                                               //    return true;
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Ret);
+                                               //  }
+                                               ilgen.MarkLabel (l3);
+                                               //  strpos++;
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Starg, 1);
+                                               //}
+                                               ilgen.Emit (OpCodes.Br, l1);
+                                               ilgen.MarkLabel (l2);
+                                               //return false;
+                                               ilgen.Emit (OpCodes.Ldc_I4_0);
+                                               ilgen.Emit (OpCodes.Ret);
+                                       }
+
+                                       goto End;
+                               }
+                               case RxOp.Branch: {
+                                       //int res = 0;
+                                       LocalBuilder local_res = 
ilgen.DeclareLocal (typeof (int));
+                                       // FIXME: Emit a branch around the rest 
of the code instead
+                                       //if (EvalByteCode (pc + 3, strpos, ref 
res)) {
+                                       Label l1 = ilgen.DefineLabel ();
+                                       MethodInfo eval = 
GetEvalMethodWithFallback (program, pc + 3, out fallback);
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       if (fallback)
+                                               ilgen.Emit (OpCodes.Ldc_I4, pc 
+ 3);
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldloca, local_res);
+                                       ilgen.Emit (OpCodes.Call, eval);
+                                       ilgen.Emit (OpCodes.Brfalse, l1);
+                                       //  strpos_result = res;
+                                       ilgen.Emit (OpCodes.Ldarg_2);
+                                       ilgen.Emit (OpCodes.Ldloc, local_res);
+                                       ilgen.Emit (OpCodes.Stind_I4);
+                                       //  return true;
+                                       ilgen.Emit (OpCodes.Ldc_I4_1);
+                                       ilgen.Emit (OpCodes.Ret);
+                                       //}
+                                       ilgen.MarkLabel (l1);
+
+                                       pc += program [pc + 1] | (program [pc + 
2] << 8);
+                                       break;
+                               }
+                               case RxOp.Char: {
+                                       //if (strpos < string_end && (str 
[strpos] == program [pc + 1])) {
+                                       Label l1 = ilgen.DefineLabel ();
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("string_end"));
+                                       ilgen.Emit (OpCodes.Bge, l1);
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("str"));
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Callvirt, typeof 
(string).GetMethod ("get_Chars"));
+                                       ilgen.Emit (OpCodes.Conv_I4);
+                                       ilgen.Emit (OpCodes.Ldc_I4, 
(int)program [pc + 1]);
+                                       ilgen.Emit (OpCodes.Bne_Un, l1);
+                                       //  strpos++;
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldc_I4_1);
+                                       ilgen.Emit (OpCodes.Add);
+                                       ilgen.Emit (OpCodes.Starg, 1);
+                                       Label l2 = ilgen.DefineLabel ();
+                                       ilgen.Emit (OpCodes.Br, l2);
+                                       //}
+                                       ilgen.MarkLabel (l1);
+                                       //return false;
+                                       ilgen.Emit (OpCodes.Ldc_I4_0);
+                                       ilgen.Emit (OpCodes.Ret);
+                                       ilgen.MarkLabel (l2);
+
+                                       pc += 2;
+                                       break;
+                               }
+                               case RxOp.True: {
+                                       //strpos_result = strpos;
+                                       ilgen.Emit (OpCodes.Ldarg_2);
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Stind_I4);
+                                       //  return true;
+                                       ilgen.Emit (OpCodes.Ldc_I4_1);
+                                       ilgen.Emit (OpCodes.Ret);
+                                       goto End;
+                               }
+                               case RxOp.False: {
+                                       //  return false;
+                                       ilgen.Emit (OpCodes.Ldc_I4_0);
+                                       ilgen.Emit (OpCodes.Ret);
+                                       goto End;
+                               }
+                               case RxOp.Bitmap: {
+                                       //if (strpos < string_end) {
+                                       Label l1 = ilgen.DefineLabel ();
+                                       Label l2 = ilgen.DefineLabel ();
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("string_end"));
+                                       ilgen.Emit (OpCodes.Bge, l1);
+                                       //  int c = str [strpos];
+                                       LocalBuilder local_c = 
ilgen.DeclareLocal (typeof (int));
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("str"));
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Callvirt, typeof 
(string).GetMethod ("get_Chars"));
+                                       ilgen.Emit (OpCodes.Conv_I4);
+                                       //  c -= program [pc + 1];
+                                       ilgen.Emit (OpCodes.Ldc_I4, 
(int)program [pc + 1]);
+                                       ilgen.Emit (OpCodes.Sub);
+                                       ilgen.Emit (OpCodes.Stloc, local_c);
+                                       length =  program [pc + 2];
+                                       //  if (c < 0 || c >= (length << 3))
+                                       //    return false;
+                                       ilgen.Emit (OpCodes.Ldloc, local_c);
+                                       ilgen.Emit (OpCodes.Ldc_I4_0);
+                                       ilgen.Emit (OpCodes.Blt, label_fail);
+                                       ilgen.Emit (OpCodes.Ldloc, local_c);
+                                       ilgen.Emit (OpCodes.Ldc_I4, length << 
3);
+                                       ilgen.Emit (OpCodes.Bge, label_fail);
+                                       pc += 3;
+
+                                       // Optimized version for small bitmaps
+                                       if (length <= 4) {
+                                               uint bitmap = program [pc];
+                                               
+                                               if (length > 1)
+                                                       bitmap |= 
((uint)program [pc + 1] << 8);
+                                               if (length > 2)
+                                                       bitmap |= 
((uint)program [pc + 2] << 16);
+                                               if (length > 3)
+                                                       bitmap |= 
((uint)program [pc + 3] << 24);
+
+                                               //if ((bitmap >> c) & 1)
+                                               ilgen.Emit (OpCodes.Ldc_I4, 
bitmap);
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_c);
+                                               ilgen.Emit (OpCodes.Shr_Un);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.And);
+                                               ilgen.Emit (OpCodes.Brfalse, 
l1);
+                                       } else {
+                                               //  if ((program [pc + (c >> 
3)] & (1 << (c & 0x7))) != 0) {
+                                               ilgen.Emit (OpCodes.Ldarg_0);
+                                               ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("program"));
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_c);
+                                               ilgen.Emit (OpCodes.Ldc_I4_3);
+                                               ilgen.Emit (OpCodes.Shr);
+                                               ilgen.Emit (OpCodes.Ldc_I4, pc);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Ldelem_I1);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_c);
+                                               ilgen.Emit (OpCodes.Ldc_I4, 7);
+                                               ilgen.Emit (OpCodes.And);
+                                               ilgen.Emit (OpCodes.Shl);
+                                               ilgen.Emit (OpCodes.And);
+                                               ilgen.Emit (OpCodes.Ldc_I4_0);
+                                               ilgen.Emit (OpCodes.Beq, l1);
+                                       }
+                                       //    strpos++;
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldc_I4_1);
+                                       ilgen.Emit (OpCodes.Add);
+                                       ilgen.Emit (OpCodes.Starg, 1);
+                                       //    continue;
+                                       ilgen.Emit (OpCodes.Br, l2);
+                                       //  }
+                                       //}
+                                       //return false;
+                                       ilgen.MarkLabel (l1);
+                                       ilgen.Emit (OpCodes.Ldc_I4_0);
+                                       ilgen.Emit (OpCodes.Ret);
+
+                                       ilgen.MarkLabel (l2);
+
+                                       pc += length;
+                                       break;
+                               }
+                               case RxOp.String: {
+                                       start = pc + 2;
+                                       length = program [pc + 1];
+                                       //if (strpos + length > string_end)
+                                       //      return false;
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldc_I4, length);
+                                       ilgen.Emit (OpCodes.Add);
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("string_end"));
+                                       ilgen.Emit (OpCodes.Bgt, label_fail);
+
+                                       /* Avoid unsafe code in Moonlight build 
*/
+#if false && !NET_2_1
+                                       LocalBuilder local_strptr = 
ilgen.DeclareLocal (typeof (char).MakePointerType ());
+                                       // char *strptr = &str.start_char + 
strpos
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("str"));
+                                       ilgen.Emit (OpCodes.Ldflda, typeof 
(String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldc_I4_1);
+                                       ilgen.Emit (OpCodes.Shl);
+                                       ilgen.Emit (OpCodes.Add);
+                                       ilgen.Emit (OpCodes.Stloc, 
local_strptr);
+
+                                       end = start + length;
+                                       for (; start < end; ++start) {
+                                               // if (*(strptr + start) != 
program [start])
+                                               //   return false;
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_strptr);
+                                               ilgen.Emit (OpCodes.Ldc_I4, 
start * 2);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Ldind_I2);
+                                               ilgen.Emit (OpCodes.Ldc_I4, 
(int)program [start]);
+                                               ilgen.Emit (OpCodes.Bne_Un, 
label_fail);
+                                       }
+
+                                       // strpos += length
+                                       ilgen.Emit (OpCodes.Ldarg_1);
+                                       ilgen.Emit (OpCodes.Ldc_I4, length);
+                                       ilgen.Emit (OpCodes.Add);
+                                       ilgen.Emit (OpCodes.Starg, 1);
+
+#else
+                                       // Allocate a local for 'str' to save 
an indirection
+                                       LocalBuilder local_str = 
ilgen.DeclareLocal (typeof (string));
+                                       ilgen.Emit (OpCodes.Ldarg_0);
+                                       ilgen.Emit (OpCodes.Ldfld, 
GetInterpreterField ("str"));
+                                       ilgen.Emit (OpCodes.Stloc, local_str);
+
+                                       // FIXME: Emit a loop for long strings
+                                       end = start + length;
+                                       for (; start < end; ++start) {
+                                               //if (str [strpos] != program 
[start])
+                                               //      return false;
+                                               ilgen.Emit (OpCodes.Ldloc, 
local_str);
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Callvirt, 
typeof (string).GetMethod ("get_Chars"));
+                                               ilgen.Emit (OpCodes.Ldc_I4, 
(int)program [start]);
+                                               ilgen.Emit (OpCodes.Bne_Un, 
label_fail);
+                                               //strpos++;
+                                               ilgen.Emit (OpCodes.Ldarg_1);
+                                               ilgen.Emit (OpCodes.Ldc_I4_1);
+                                               ilgen.Emit (OpCodes.Add);
+                                               ilgen.Emit (OpCodes.Starg, 1);
+                                       }
+#endif
+
+                                       pc = end;
+                                       break;
+                               }
+                               case RxOp.Jump:
+                                       pc += program [pc + 1] | (program [pc + 
2] << 8);
+                                       continue;
+                               default:
+                                       Console.WriteLine ("Opcode " + op + " 
not supported.");
+                                       return null;
+                               }
+                       }
+
+               End:
+                       ilgen.MarkLabel (label_fail);
+                       ilgen.Emit (OpCodes.Ldc_I4_0);
+                       ilgen.Emit (OpCodes.Ret);
+
+                       return m;
+               }
+       }
+#else
+       class CILCompiler : RxCompiler {
+       }
+#endif
+
        class RxInterpreterFactory : IMachineFactory {
-               public RxInterpreterFactory (byte[] program) {
+               public RxInterpreterFactory (byte[] program, EvalDelegate 
eval_del) {
                        this.program = program;
+                       this.eval_del = eval_del;
                }
                
                public IMachine NewInstance () {
-                       return new RxInterpreter (program);
+                       return new RxInterpreter (program, eval_del);
                }
 
                public int GroupCount {
@@ -711,6 +1207,7 @@
 
                private IDictionary mapping;
                private byte[] program;
+               private EvalDelegate eval_del;
                private string[] namesMapping;
        }
 

Modified: trunk/mcs/class/System/System.Text.RegularExpressions/RxInterpreter.cs
===================================================================
--- trunk/mcs/class/System/System.Text.RegularExpressions/RxInterpreter.cs      
2008-02-13 14:29:49 UTC (rev 95579)
+++ trunk/mcs/class/System/System.Text.RegularExpressions/RxInterpreter.cs      
2008-02-13 14:30:06 UTC (rev 95580)
@@ -5,6 +5,8 @@
 
 namespace System.Text.RegularExpressions {
 
+       internal delegate bool EvalDelegate (RxInterpreter interp, int strpos, 
ref int strpos_result);
+
        class RxInterpreter: BaseMachine {
                byte[] program;
                string str;
@@ -13,6 +15,7 @@
                int group_count;
                int match_start;
                int[] groups;
+               EvalDelegate eval_del; // optimized EvalByteCode method created 
by the CILCompiler
 
                Mark[] marks = null; // mark stack
                int mark_start; // start of current checkpoint
@@ -27,9 +30,10 @@
                        return val;
                }
 
-               public RxInterpreter (byte[] program)
+               public RxInterpreter (byte[] program, EvalDelegate eval_del)
                {
                        this.program = program;
+                       this.eval_del = eval_del;
                        group_count = 1 + (program [1] | (program [2] << 8));
                        groups = new int [group_count];
                }
@@ -39,7 +43,14 @@
                        string_start = start;
                        string_end = end;
                        int res = 0;
-                       if (EvalByteCode (11, start, ref res)) {
+
+                       bool match;
+                       if (eval_del != null) {
+                               match = eval_del (this, start, ref res);
+                       } else {
+                               match = EvalByteCode (11, start, ref res);
+                       }
+                       if (match) {
                                Match m = new Match (regex, this, text, end, 0, 
match_start, res - match_start);
                                return m;
                        }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to