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)
{
return local;
}
- public void EmitLoad (Expression expression)
+ public void EmitLoadAddress (Expression expression)
+ {
+ ig.Emit (OpCodes.Ldloca, EmitStored (expression));
+ }
+
+ public void EmitLoadSubject (Expression expression)
{
if (expression.Type.IsValueType) {
- var local = EmitStored (expression);
- ig.Emit (OpCodes.Ldloca, local);
- } else
- expression.Emit (this);
+ EmitLoadAddress (expression);
+ return;
+ }
+
+ Emit (expression);
+ }
+
+ public void EmitLoadSubject (LocalBuilder local)
+ {
+ if (local.LocalType.IsValueType) {
+ EmitLoadAddress (local);
+ return;
+ }
+
+ EmitLoad (local);
+ }
+
+ public void EmitLoadAddress (LocalBuilder local)
+ {
+ ig.Emit (OpCodes.Ldloca, local);
}
public void EmitLoad (LocalBuilder local)
public void EmitCall (LocalBuilder local, ReadOnlyCollection<Expression> arguments, MethodInfo method)
{
- EmitLoad (local);
+ EmitLoadSubject (local);
EmitArguments (method, arguments);
EmitCall (method);
}
+ public void EmitCall (LocalBuilder local, MethodInfo method)
+ {
+ EmitLoadSubject (local);
+ EmitCall (method);
+ }
+
+ public void EmitCall (Expression expression, MethodInfo method)
+ {
+ if (!method.IsStatic)
+ EmitLoadSubject (expression);
+
+ EmitCall (method);
+ }
+
public void EmitCall (Expression expression, ReadOnlyCollection<Expression> arguments, MethodInfo method)
{
if (!method.IsStatic)
- EmitLoad (expression);
+ EmitLoadSubject (expression);
EmitArguments (method, arguments);
EmitCall (method);
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;
+ return context.AddGlobal (CreateStrongBox (value, type));
}
- static object CreateStrongBox (object value, Type type)
+ public void EmitCreateDelegate (LambdaExpression lambda)
{
- return Activator.CreateInstance (
- type.MakeStrongBoxType (), value);
- }
- }
-
- class DynamicEmitContext : EmitContext {
-
- DynamicMethod method;
-
- static object mlock = new object ();
- static int method_count;
+ EmitScope ();
- public DynamicMethod Method {
- get { return method; }
- }
+ ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda));
+ ig.Emit (OpCodes.Ldnull);
- public DynamicEmitContext (LambdaExpression lambda)
- : base (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 ();
+ ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate"));
- owner.EmitBody (this);
+ ig.Emit (OpCodes.Castclass, lambda.Type);
}
- public override Delegate CreateDelegate ()
+ int AddChildContext (LambdaExpression lambda)
{
- return method.CreateDelegate (owner.Type, new ExecutionScope (globals.ToArray ()));
+ return context.AddCompilationUnit (lambda);
}
- static string GenerateName ()
- {
- lock (mlock) {
- return "lambda_method-" + (method_count++);
- }
- }
- }
-
-#if !NET_2_1
- class DebugEmitContext : DynamicEmitContext {
-
- public DebugEmitContext (LambdaExpression lambda)
- : base (lambda)
+ static object CreateStrongBox (object value, Type type)
{
- 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 Activator.CreateInstance (
+ type.MakeStrongBoxType (), value);
}
}
-#endif
}