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=c4b2ad654aa4e763af0d38d4e2da65a359058c3d;hpb=15d5f962e69c398ba2f0a4ca836284e5a4ec8969;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 c4b2ad654aa..221571dff41 100644 --- a/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs +++ b/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs @@ -28,38 +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; + List globals = new List (); + List units = new List (); - public ILGenerator ig; + 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 abstract MethodInfo Method { get; } + public int AddCompilationUnit (LambdaExpression lambda) + { + var context = new EmitContext (this, lambda); + var unit = AddItemToList (context, units); + context.Emit (); + return unit; + } - static object mlock = new object (); - static int method_count; + public Delegate CreateDelegate () + { + return CreateDelegate (0, new ExecutionScope (this)); + } - protected EmitContext (LambdaExpression lambda) + public Delegate CreateDelegate (int unit, ExecutionScope scope) { + return units [unit].CreateDelegate (scope); + } + } + + class EmitContext { + + LambdaExpression owner; + CompilationContext context; + DynamicMethod method; + + public ILGenerator ig; + + public EmitContext (CompilationContext context, LambdaExpression lambda) + { + this.context = context; this.owner = lambda; - param_types = owner.Parameters.Select (p => p.Type).ToArray (); + 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); - return new DynamicEmitContext (lambda); + for (int i = 0; i < parameters.Count; i++) + types [i + 1] = parameters [i].Type; + + return types; } public int GetParameterPosition (ParameterExpression p) @@ -68,99 +119,230 @@ 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 Delegate CreateDelegate (ExecutionScope scope) + { + return method.CreateDelegate (owner.Type, scope); + } + + public void Emit (Expression expression) + { + expression.Emit (this); } - public abstract Delegate CreateDelegate (); + public LocalBuilder EmitStored (Expression expression) + { + var local = ig.DeclareLocal (expression.Type); + expression.Emit (this); + ig.Emit (OpCodes.Stloc, local); - public abstract void Emit (); + return local; + } - protected static string GenerateName () + public void EmitLoadAddress (Expression expression) { - lock (mlock) { - return "lambda_method-" + (method_count++); + ig.Emit (OpCodes.Ldloca, EmitStored (expression)); + } + + public void EmitLoadSubject (Expression expression) + { + if (expression.Type.IsValueType) { + EmitLoadAddress (expression); + return; } + + Emit (expression); } - } - class DynamicEmitContext : EmitContext { + public void EmitLoadSubject (LocalBuilder local) + { + if (local.LocalType.IsValueType) { + EmitLoadAddress (local); + return; + } - DynamicMethod method; + EmitLoad (local); + } - public override MethodInfo Method { - get { return method; } + public void EmitLoadAddress (LocalBuilder local) + { + ig.Emit (OpCodes.Ldloca, local); } - public DynamicEmitContext (LambdaExpression lambda) - : base (lambda) + public void EmitLoad (LocalBuilder local) { - // - // We probably want to use the 3.5 new API calls to associate - // the method with the "sandboxed" Assembly, instead am currently - // dumping these types in this class - // - Type owner_of_code = typeof (EmitContext); + ig.Emit (OpCodes.Ldloc, local); + } - // - // FIXME: Need to force this to be verifiable, see: - // https://bugzilla.novell.com/show_bug.cgi?id=355005 - // - method = new DynamicMethod ("lambda_method", lambda.Body.Type, param_types, owner_of_code); - ig = method.GetILGenerator (); + public void EmitCall (LocalBuilder local, ReadOnlyCollection arguments, MethodInfo method) + { + EmitLoadSubject (local); + EmitArguments (method, arguments); + EmitCall (method); } - public override Delegate CreateDelegate () + public void EmitCall (LocalBuilder local, MethodInfo method) { - return method.CreateDelegate (owner.Type); + EmitLoadSubject (local); + EmitCall (method); } - public override void Emit () + public void EmitCall (Expression expression, MethodInfo method) { - owner.Emit (this); + if (!method.IsStatic) + EmitLoadSubject (expression); + + EmitCall (method); } - } - class DebugEmitContext : EmitContext { + public void EmitCall (Expression expression, ReadOnlyCollection arguments, MethodInfo method) + { + if (!method.IsStatic) + EmitLoadSubject (expression); - AssemblyBuilder assembly; - TypeBuilder type; - MethodBuilder method; + EmitArguments (method, arguments); + EmitCall (method); + } - public override MethodInfo Method { - get { return 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 ( + method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, + method); } - public DebugEmitContext (LambdaExpression lambda) - : base (lambda) + public void EmitNullableHasValue (LocalBuilder local) { - var name = GenerateName (); - var file_name = name + ".dll"; + EmitCall (local, "get_HasValue"); + } - assembly = AppDomain.CurrentDomain.DefineDynamicAssembly ( - new AssemblyName (file_name), AssemblyBuilderAccess.RunAndSave, Path.GetTempPath ()); + public void EmitNullableInitialize (LocalBuilder local) + { + ig.Emit (OpCodes.Ldloca, local); + ig.Emit (OpCodes.Initobj, local.LocalType); + ig.Emit (OpCodes.Ldloc, local); + } - type = assembly.DefineDynamicModule (file_name, file_name).DefineType ("Linq", TypeAttributes.Public); + public void EmitNullableGetValue (LocalBuilder local) + { + EmitCall (local, "get_Value"); + } - method = type.DefineMethod (name, MethodAttributes.Public | MethodAttributes.Static, owner.Body.Type, param_types); - ig = method.GetILGenerator (); + public void EmitNullableGetValueOrDefault (LocalBuilder local) + { + EmitCall (local, "GetValueOrDefault"); } - public override Delegate CreateDelegate () + void EmitCall (LocalBuilder local, string method_name) { - return Delegate.CreateDelegate (owner.Type, GetMethod ()); + EmitCall (local, local.LocalType.GetMethod (method_name, Type.EmptyTypes)); } - MethodInfo GetMethod () + public void EmitNullableNew (Type of) { - return type.GetMethod (method.Name, BindingFlags.Static | BindingFlags.Public); + ig.Emit (OpCodes.Newobj, of.GetConstructor (new [] { of.GetFirstGenericArgument () })); } - public override void Emit () + public void EmitCollection (IEnumerable collection) where T : Expression { - owner.Emit (this); + foreach (var expression in collection) + expression.Emit (this); + } + + public void EmitCollection (IEnumerable initializers, LocalBuilder local) + { + foreach (var initializer in initializers) + initializer.Emit (this, local); + } + + public void EmitCollection (IEnumerable bindings, LocalBuilder local) + { + foreach (var binding in bindings) + binding.Emit (this, local); + } + + public void EmitIsInst (Expression expression, Type candidate) + { + expression.Emit (this); + + var type = expression.Type; + + if (type.IsValueType) + ig.Emit (OpCodes.Box, type); + + ig.Emit (OpCodes.Isinst, candidate); + } - type.CreateType (); - assembly.Save (assembly.GetName ().FullName); + public void EmitScope () + { + ig.Emit (OpCodes.Ldarg_0); + } + + public void EmitReadGlobal (object global) + { + EmitReadGlobal (global, global.GetType ()); + } + + public void EmitReadGlobal (object global, Type type) + { + EmitScope (); + + ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Globals")); + + ig.Emit (OpCodes.Ldc_I4, AddGlobal (global, type)); + ig.Emit (OpCodes.Ldelem, typeof (object)); + + var strongbox = type.MakeStrongBoxType (); + + ig.Emit (OpCodes.Isinst, strongbox); + ig.Emit (OpCodes.Ldfld, strongbox.GetField ("Value")); + } + + int AddGlobal (object value, Type type) + { + return context.AddGlobal (CreateStrongBox (value, type)); + } + + public void EmitCreateDelegate (LambdaExpression lambda) + { + EmitScope (); + + ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda)); + ig.Emit (OpCodes.Ldnull); + + ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate")); + + ig.Emit (OpCodes.Castclass, lambda.Type); + } + + int AddChildContext (LambdaExpression lambda) + { + return context.AddCompilationUnit (lambda); + } + + static object CreateStrongBox (object value, Type type) + { + return Activator.CreateInstance ( + type.MakeStrongBoxType (), value); } } }