namespace System.Linq.Expressions {
- abstract class EmitContext {
+ class CompilationContext {
- protected LambdaExpression owner;
- protected Type [] param_types;
- protected Type return_type;
+ List<object> globals = new List<object> ();
+ List<EmitContext> units = new List<EmitContext> ();
- protected List<object> globals = new List<object> ();
+ public int AddGlobal (object global)
+ {
+ return AddItemToList (global, globals);
+ }
+
+ public object [] GetGlobals ()
+ {
+ return globals.ToArray ();
+ }
+
+ static int AddItemToList<T> (T item, IList<T> list)
+ {
+ list.Add (item);
+ return list.Count - 1;
+ }
+
+ public int AddCompilationUnit (LambdaExpression lambda)
+ {
+ var context = new EmitContext (this, lambda);
+ var unit = AddItemToList (context, units);
+ context.Emit ();
+ return unit;
+ }
+
+ public Delegate CreateDelegate ()
+ {
+ return CreateDelegate (0, new ExecutionScope (this));
+ }
+
+ public Delegate CreateDelegate (int unit, ExecutionScope scope)
+ {
+ return units [unit].CreateDelegate (scope);
+ }
+ }
+
+ class EmitContext {
+
+ LambdaExpression owner;
+ CompilationContext context;
+ DynamicMethod method;
public ILGenerator ig;
- protected EmitContext (LambdaExpression lambda)
+ public EmitContext (CompilationContext context, LambdaExpression lambda)
{
+ this.context = context;
this.owner = lambda;
- param_types = CreateParameterTypes (owner.Parameters);
- return_type = owner.GetReturnType ();
+ method = new DynamicMethod ("lambda_method", owner.GetReturnType (),
+ CreateParameterTypes (owner.Parameters), typeof (ExecutionScope), true);
+
+ ig = method.GetILGenerator ();
+ }
+
+ public void Emit ()
+ {
+ owner.EmitBody (this);
}
static Type [] CreateParameterTypes (ReadOnlyCollection<ParameterExpression> parameters)
return types;
}
- public static EmitContext Create (LambdaExpression lambda)
- {
-#if !NET_2_1
- if (Environment.GetEnvironmentVariable ("LINQ_DBG") != null)
- return new DebugEmitContext (lambda);
-#endif
- return new DynamicEmitContext (lambda);
- }
-
public int GetParameterPosition (ParameterExpression p)
{
int position = owner.Parameters.IndexOf (p);
return position + 1; // + 1 because 0 is the ExecutionScope
}
- public abstract Delegate CreateDelegate ();
+ public Delegate CreateDelegate (ExecutionScope scope)
+ {
+ return method.CreateDelegate (owner.Type, scope);
+ }
public void Emit (Expression expression)
{
if (parameter.ParameterType.IsByRef) {
ig.Emit (OpCodes.Ldloca, EmitStored (argument));
- return;
+ continue;
}
Emit (arguments [i]);
method);
}
+ public void EmitNullableHasValue (LocalBuilder local)
+ {
+ EmitCall (local, "get_HasValue");
+ }
+
+ public void EmitNullableInitialize (LocalBuilder local)
+ {
+ ig.Emit (OpCodes.Ldloca, local);
+ ig.Emit (OpCodes.Initobj, local.LocalType);
+ ig.Emit (OpCodes.Ldloc, local);
+ }
+
+ public void EmitNullableGetValue (LocalBuilder local)
+ {
+ EmitCall (local, "get_Value");
+ }
+
+ public void EmitNullableGetValueOrDefault (LocalBuilder local)
+ {
+ EmitCall (local, "GetValueOrDefault");
+ }
+
+ void EmitCall (LocalBuilder local, string method_name)
+ {
+ EmitCall (local, local.LocalType.GetMethod (method_name, Type.EmptyTypes));
+ }
+
+ public void EmitNullableNew (Type of)
+ {
+ ig.Emit (OpCodes.Newobj, of.GetConstructor (new [] { of.GetFirstGenericArgument () }));
+ }
+
public void EmitCollection<T> (IEnumerable<T> collection) where T : Expression
{
foreach (var expression in collection)
{
expression.Emit (this);
- if (expression.Type.IsValueType)
- ig.Emit (OpCodes.Box, expression.Type);
+ var type = expression.Type;
+
+ if (type.IsValueType)
+ ig.Emit (OpCodes.Box, type);
ig.Emit (OpCodes.Isinst, candidate);
}
int AddGlobal (object value, Type type)
{
- globals.Add (CreateStrongBox (value, type));
- return globals.Count - 1;
- }
-
- static object CreateStrongBox (object value, Type type)
- {
- return Activator.CreateInstance (
- type.MakeStrongBoxType (), value);
- }
- }
-
- class DynamicEmitContext : EmitContext {
-
- DynamicMethod method;
-
- public DynamicMethod Method {
- get { return method; }
+ return context.AddGlobal (CreateStrongBox (value, type));
}
- public DynamicEmitContext (LambdaExpression lambda)
- : base (lambda)
+ public void EmitCreateDelegate (LambdaExpression lambda)
{
- // FIXME: Need to force this to be verifiable, see:
- // https://bugzilla.novell.com/show_bug.cgi?id=355005
- method = new DynamicMethod (GenerateName (), return_type, param_types, typeof (ExecutionScope), true);
- ig = method.GetILGenerator ();
+ EmitScope ();
- owner.EmitBody (this);
- }
+ ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda));
+ ig.Emit (OpCodes.Ldnull);
- public override Delegate CreateDelegate ()
- {
- return method.CreateDelegate (owner.Type, new ExecutionScope (globals.ToArray ()));
- }
+ ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate"));
- protected virtual string GenerateName ()
- {
- return "lambda_method";
+ ig.Emit (OpCodes.Castclass, lambda.Type);
}
- }
-
-#if !NET_2_1
- class DebugEmitContext : DynamicEmitContext {
- static object mlock = new object ();
- static int method_count;
-
- public DebugEmitContext (LambdaExpression lambda)
- : base (lambda)
+ int AddChildContext (LambdaExpression lambda)
{
- var name = Method.Name;
- var file_name = name + ".dll";
-
- var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly (
- new AssemblyName (name), AssemblyBuilderAccess.RunAndSave, Path.GetTempPath ());
-
- var type = assembly.DefineDynamicModule (file_name, file_name).DefineType ("Linq", TypeAttributes.Public);
-
- var method = type.DefineMethod (name, MethodAttributes.Public | MethodAttributes.Static, return_type, param_types);
- ig = method.GetILGenerator ();
-
- owner.EmitBody (this);
-
- type.CreateType ();
- assembly.Save (file_name);
+ return context.AddCompilationUnit (lambda);
}
- protected override string GenerateName ()
+ static object CreateStrongBox (object value, Type type)
{
- lock (mlock) {
- return "lambda_method-" + (method_count++);
- }
+ return Activator.CreateInstance (
+ type.MakeStrongBoxType (), value);
}
}
-#endif
}