/// <summary> /// Creates a lambda compiler that will compile to a dynamic method /// </summary> private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda) { Type[] parameterTypes = GetParameterTypes(lambda, typeof(Closure)); int lambdaMethodIndex = Interlocked.Increment(ref s_lambdaMethodIndex); var method = new DynamicMethod(lambda.Name ?? ("lambda_method" + lambdaMethodIndex.ToString()), lambda.ReturnType, parameterTypes, true); _tree = tree; _lambda = lambda; _method = method; // In a Win8 immersive process user code is not allowed to access non-W8P framework APIs through // reflection or RefEmit. Framework code, however, is given an exemption. // This is to make sure that user code cannot access non-W8P framework APIs via ExpressionTree. // TODO: This API is not available, is there an alternative way to achieve the same. // method.ProfileAPICheck = true; _ilg = method.GetILGenerator(); _hasClosureArgument = true; // These are populated by AnalyzeTree/VariableBinder _scope = tree.Scopes[lambda]; _boundConstants = tree.Constants[lambda]; InitializeMethod(); }
/// <summary> /// Creates a lambda compiler that will compile into the provided MethodBuilder /// </summary> private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda, MethodBuilder method) { var scope = tree.Scopes[lambda]; var hasClosureArgument = scope.NeedsClosure; Type[] paramTypes = GetParameterTypes(lambda, hasClosureArgument ? typeof(Closure) : null); method.SetReturnType(lambda.ReturnType); method.SetParameters(paramTypes); var parameters = lambda.Parameters; // parameters are index from 1, with closure argument we need to skip the first arg int startIndex = hasClosureArgument ? 2 : 1; for (int i = 0, n = parameters.Count; i < n; i++) { method.DefineParameter(i + startIndex, ParameterAttributes.None, parameters[i].Name); } _tree = tree; _lambda = lambda; _typeBuilder = (TypeBuilder)method.DeclaringType; _method = method; _hasClosureArgument = hasClosureArgument; _ilg = method.GetILGenerator(); // These are populated by AnalyzeTree/VariableBinder _scope = scope; _boundConstants = tree.Constants[lambda]; InitializeMethod(); }
/// <summary> /// Creates a compiler backed by dynamic method. Sometimes (when debugging is required) the dynamic /// method is actually a 'fake' dynamic method and is backed by static type created specifically for /// the one method /// </summary> private static LambdaCompiler CreateDynamicCompiler( AnalyzedTree tree, LambdaExpression lambda, string methodName, Type returnType, IList <Type> paramTypes, IList <string> paramNames, bool emitDebugSymbols, bool forceDynamic) { Assert.NotEmpty(methodName); Assert.NotNull(returnType); Assert.NotNullItems(paramTypes); LambdaCompiler lc; // // Generate a static method if either // 1) we want to dump all geneated IL to an assembly on disk (SaveSnippets on) // 2) the method is debuggable, i.e. DebugMode is on and a source unit is associated with the method // if ((Snippets.Shared.SaveSnippets || emitDebugSymbols) && !forceDynamic) { var typeBuilder = Snippets.Shared.DefineType(methodName, typeof(object), false, false, emitDebugSymbols); lc = CreateStaticCompiler( tree, lambda, typeBuilder, methodName, TypeUtils.PublicStatic, returnType, paramTypes, paramNames, true, // dynamicMethod emitDebugSymbols ); } else { Type[] parameterTypes = paramTypes.AddFirst(typeof(Closure)); DynamicMethod target = Snippets.Shared.CreateDynamicMethod(methodName, returnType, parameterTypes); lc = new LambdaCompiler( tree, lambda, null, // typeGen target, target.GetILGenerator(), parameterTypes, true, // dynamicMethod false // emitDebugSymbols ); } return(lc); }
/// <summary> /// Creates a lambda compiler for an inlined lambda /// </summary> private LambdaCompiler(LambdaCompiler parent, LambdaExpression lambda) { _tree = parent._tree; _lambda = lambda; _method = parent._method; _ilg = parent._ilg; _hasClosureArgument = parent._hasClosureArgument; _typeBuilder = parent._typeBuilder; _scope = _tree.Scopes[lambda]; _boundConstants = parent._boundConstants; }
/// <summary> /// Mutates the MethodBuilder parameter, filling in IL, parameters, /// and return type. /// /// (probably shouldn't be modifying parameters/return type...) /// </summary> internal static void Compile(LambdaExpression lambda, MethodBuilder method) { // 1. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); // 2. Create lambda compiler LambdaCompiler c = new LambdaCompiler(tree, lambda, method); // 3. Emit c.EmitLambdaBody(); }
/// <summary> /// Compiler entry point /// </summary> /// <param name="lambda">LambdaExpression to compile.</param> /// <returns>The compiled delegate.</returns> internal static Delegate Compile(LambdaExpression lambda) { // 1. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); // 2. Create lambda compiler LambdaCompiler c = new LambdaCompiler(tree, lambda); // 3. Emit c.EmitLambdaBody(); // 4. Return the delegate. return(c.CreateDelegate()); }
/// <summary> /// Creates a LambdaCompiler backed by a method on a static type /// </summary> private static LambdaCompiler CreateStaticCompiler( AnalyzedTree tree, LambdaExpression lambda, TypeBuilder typeBuilder, string name, MethodAttributes attributes, Type retType, IList <Type> paramTypes, IList <string> paramNames, bool dynamicMethod, bool emitDebugSymbols) { Assert.NotNull(name, retType); bool closure = tree.Scopes[lambda].NeedsClosure; Type[] parameterTypes; if (dynamicMethod || closure) { parameterTypes = paramTypes.AddFirst(typeof(Closure)); } else { parameterTypes = paramTypes.ToArray(); } MethodBuilder mb = typeBuilder.DefineMethod(name, attributes, retType, parameterTypes); LambdaCompiler lc = new LambdaCompiler( tree, lambda, typeBuilder, mb, mb.GetILGenerator(), parameterTypes, dynamicMethod, emitDebugSymbols ); if (paramNames != null) { // parameters are index from 1, with closure argument we need to skip the first arg int startIndex = (dynamicMethod || closure) ? 2 : 1; for (int i = 0; i < paramNames.Count; i++) { mb.DefineParameter(i + startIndex, ParameterAttributes.None, paramNames[i]); } } return(lc); }
/// <summary> /// Creates a lambda compiler for an inlined lambda /// </summary> private LambdaCompiler( LambdaCompiler parent, LambdaExpression lambda, InvocationExpression invocation) { _tree = parent._tree; _lambda = lambda; _method = parent._method; _ilg = parent._ilg; _hasClosureArgument = parent._hasClosureArgument; _typeBuilder = parent._typeBuilder; // inlined scopes are associated with invocation, not with the lambda _scope = _tree.Scopes[invocation]; _boundConstants = parent._boundConstants; }
/// <summary> /// Compiler entry point /// </summary> /// <param name="lambda">LambdaExpression to compile.</param> /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param> /// <returns>The compiled delegate.</returns> internal static Delegate Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator) { lambda.ValidateArgumentCount(); // 1. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); // 2. Create lambda compiler LambdaCompiler c = new LambdaCompiler(tree, lambda, debugInfoGenerator); // 3. Emit c.EmitLambdaBody(); // 4. Return the delegate. return(c.CreateDelegate()); }
/// <summary> /// Creates a lambda compiler that will compile to a dynamic method /// </summary> private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda) { Type[] parameterTypes = GetParameterTypes(lambda, typeof(Closure)); var method = new DynamicMethod(lambda.Name ?? "lambda_method", lambda.ReturnType, parameterTypes, true); _tree = tree; _lambda = lambda; _method = method; _ilg = method.GetILGenerator(); _hasClosureArgument = true; // These are populated by AnalyzeTree/VariableBinder _scope = tree.Scopes[lambda]; _boundConstants = tree.Constants[lambda]; InitializeMethod(); }
/// <summary> /// Compiler entry point /// </summary> /// <param name="lambda">LambdaExpression to compile.</param> /// <param name="method">Product of compilation</param> /// <param name="delegateType">Type of the delegate to create</param> /// <param name="emitDebugSymbols">True to emit debug symbols, false otherwise.</param> /// <param name="forceDynamic">Force dynamic method regardless of save assemblies.</param> /// <returns>The compiled delegate.</returns> internal static Delegate CompileLambda(LambdaExpression lambda, Type delegateType, bool emitDebugSymbols, bool forceDynamic, out MethodInfo method) { // 1. Create signature List <Type> types; List <string> names; string name; Type returnType; ComputeSignature(lambda, out types, out names, out name, out returnType); // 2. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); // 3. Create lambda compiler LambdaCompiler c = CreateDynamicCompiler(tree, lambda, name, returnType, types, null, emitDebugSymbols, forceDynamic); // 4. Emit c.EmitLambdaBody(null); // 5. Return the delegate. return(c.CreateDelegate(delegateType, out method)); }
private LambdaCompiler( AnalyzedTree tree, LambdaExpression lambda, TypeBuilder typeBuilder, MethodInfo method, ILGenerator ilg, IList <Type> paramTypes, bool dynamicMethod, bool emitDebugSymbols) { ContractUtils.Requires(dynamicMethod || method.IsStatic, "dynamicMethod"); _tree = tree; _lambda = lambda; _typeBuilder = typeBuilder; _method = method; _paramTypes = new ReadOnlyCollection <Type>(paramTypes); _dynamicMethod = dynamicMethod; // These are populated by AnalyzeTree/VariableBinder _scope = tree.Scopes[lambda]; _boundConstants = tree.Constants[lambda]; if (!dynamicMethod && _boundConstants.Count > 0) { throw Error.RtConstRequiresBundDelegate(); } _ilg = new ILGen(ilg); Debug.Assert(!emitDebugSymbols || _typeBuilder != null, "emitting debug symbols requires a TypeBuilder"); _emitDebugSymbols = emitDebugSymbols; // See if we can find a return label, so we can emit better IL AddReturnLabel(_lambda.Body); _boundConstants.EmitCacheConstants(this); }