X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Core%2FSystem.Linq.Expressions%2FEmitContext.cs;h=221571dff419032f071ec8951a19c3fd0fd46f8b;hb=3f5524d8ed5a4b6c66df07581474cebddd30da2d;hp=a2f53b8a48bd00472336d19af8799efa35b4c1c0;hpb=6f94553690b1cd6487bcc206aec7f58c99f77adb;p=mono.git diff --git a/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs b/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs index a2f53b8a48b..221571dff41 100644 --- a/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs +++ b/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs @@ -28,36 +28,89 @@ // using System; +using System.Collections.ObjectModel; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; namespace System.Linq.Expressions { - abstract class EmitContext { + class CompilationContext { - protected LambdaExpression owner; - protected Type [] param_types; - protected Type return_type; + List globals = new List (); + List units = new List (); + + public int AddGlobal (object global) + { + return AddItemToList (global, globals); + } + + public object [] GetGlobals () + { + return globals.ToArray (); + } + + static int AddItemToList (T item, IList 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 = owner.Parameters.Select (p => p.Type).ToArray (); - 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); } - public static EmitContext Create (LambdaExpression lambda) + static Type [] CreateParameterTypes (ReadOnlyCollection parameters) { - if (Environment.GetEnvironmentVariable ("LINQ_DBG") != null) - return new DebugEmitContext (lambda); + var types = new Type [parameters.Count + 1]; + types [0] = typeof (ExecutionScope); + + for (int i = 0; i < parameters.Count; i++) + types [i + 1] = parameters [i].Type; - return new DynamicEmitContext (lambda); + return types; } public int GetParameterPosition (ParameterExpression p) @@ -66,10 +119,13 @@ namespace System.Linq.Expressions { if (position == -1) throw new InvalidOperationException ("Parameter not in scope"); - return position; + 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) { @@ -85,13 +141,34 @@ namespace System.Linq.Expressions { 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) @@ -99,22 +176,53 @@ namespace System.Linq.Expressions { ig.Emit (OpCodes.Ldloc, local); } - public void EmitCall (LocalBuilder local, IEnumerable arguments, MethodInfo method) + public void EmitCall (LocalBuilder local, ReadOnlyCollection arguments, MethodInfo method) { - EmitLoad (local); - EmitCollection (arguments); + EmitLoadSubject (local); + EmitArguments (method, arguments); EmitCall (method); } - public void EmitCall (Expression expression, IEnumerable arguments, MethodInfo method) + public void EmitCall (LocalBuilder local, MethodInfo method) { - if (expression != null) - EmitLoad (expression); + EmitLoadSubject (local); + EmitCall (method); + } + + public void EmitCall (Expression expression, MethodInfo method) + { + if (!method.IsStatic) + EmitLoadSubject (expression); - EmitCollection (arguments); EmitCall (method); } + public void EmitCall (Expression expression, ReadOnlyCollection arguments, MethodInfo method) + { + if (!method.IsStatic) + EmitLoadSubject (expression); + + EmitArguments (method, arguments); + EmitCall (method); + } + + void EmitArguments (MethodInfo method, ReadOnlyCollection arguments) + { + var parameters = method.GetParameters (); + + for (int i = 0; i < parameters.Length; i++) { + var parameter = parameters [i]; + var argument = arguments [i]; + + if (parameter.ParameterType.IsByRef) { + ig.Emit (OpCodes.Ldloca, EmitStored (argument)); + continue; + } + + Emit (arguments [i]); + } + } + public void EmitCall (MethodInfo method) { ig.Emit ( @@ -122,6 +230,38 @@ namespace System.Linq.Expressions { 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 (IEnumerable collection) where T : Expression { foreach (var expression in collection) @@ -144,77 +284,65 @@ namespace System.Linq.Expressions { { expression.Emit (this); - if (expression.Type.IsValueType) - ig.Emit (OpCodes.Box, expression.Type); - - ig.Emit (OpCodes.Isinst, candidate); - } - } + var type = expression.Type; - class DynamicEmitContext : EmitContext { + if (type.IsValueType) + ig.Emit (OpCodes.Box, type); - DynamicMethod method; - - static object mlock = new object (); - static int method_count; - - public DynamicMethod Method { - get { return method; } + ig.Emit (OpCodes.Isinst, candidate); } - public DynamicEmitContext (LambdaExpression lambda) - : base (lambda) + public void EmitScope () { - // 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 (EmitContext), true); - ig = method.GetILGenerator (); - - owner.Emit (this); + ig.Emit (OpCodes.Ldarg_0); } - public override Delegate CreateDelegate () + public void EmitReadGlobal (object global) { - return method.CreateDelegate (owner.Type); + EmitReadGlobal (global, global.GetType ()); } - static string GenerateName () + public void EmitReadGlobal (object global, Type type) { - lock (mlock) { - return "lambda_method-" + (method_count++); - } - } - } + EmitScope (); - class DebugEmitContext : EmitContext { + ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Globals")); - DynamicEmitContext dynamic_context; + ig.Emit (OpCodes.Ldc_I4, AddGlobal (global, type)); + ig.Emit (OpCodes.Ldelem, typeof (object)); - public DebugEmitContext (LambdaExpression lambda) - : base (lambda) - { - dynamic_context = new DynamicEmitContext (lambda); + var strongbox = type.MakeStrongBoxType (); + + ig.Emit (OpCodes.Isinst, strongbox); + ig.Emit (OpCodes.Ldfld, strongbox.GetField ("Value")); + } - var name = dynamic_context.Method.Name; - var file_name = name + ".dll"; + int AddGlobal (object value, Type type) + { + return context.AddGlobal (CreateStrongBox (value, type)); + } - var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly ( - new AssemblyName (name), AssemblyBuilderAccess.RunAndSave, Path.GetTempPath ()); + public void EmitCreateDelegate (LambdaExpression lambda) + { + EmitScope (); - var type = assembly.DefineDynamicModule (file_name, file_name).DefineType ("Linq", TypeAttributes.Public); + ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda)); + ig.Emit (OpCodes.Ldnull); - var method = type.DefineMethod (name, MethodAttributes.Public | MethodAttributes.Static, return_type, param_types); - ig = method.GetILGenerator (); + ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate")); - owner.Emit (this); + ig.Emit (OpCodes.Castclass, lambda.Type); + } - type.CreateType (); - assembly.Save (file_name); + int AddChildContext (LambdaExpression lambda) + { + return context.AddCompilationUnit (lambda); } - public override Delegate CreateDelegate () + static object CreateStrongBox (object value, Type type) { - return dynamic_context.CreateDelegate (); + return Activator.CreateInstance ( + type.MakeStrongBoxType (), value); } } }