Beispiel #1
0
        private static bool TryEmit(this LambdaExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)
        {
            var lambdaClosureIndex = context.StoredExpressions.GetIndex(expression);

            if (lambdaClosureIndex == -1)
            {
                return(false);
            }

            var lambdaIndex = context.NestedLambdas.GetIndex(expression);

            if (lambdaIndex == -1)
            {
                return(false);
            }

            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, context.Target.Fields[lambdaClosureIndex]);

            if (context.HasCapturedVariablesArgument)
            {
                if (!context.IsNestedLambda)
                {
                    generator.Emit(OpCodes.Ldloc, context.CapturedArgumentsHolderVariable);
                }
                else
                {
                    generator.Emit(OpCodes.Ldarg_1);
                }
            }

            var lambda = context.NestedLambdas[lambdaIndex];

            var lambdaExpression = lambda.Key;
            var variables        = lambda.Value;

            var nestedParameters = lambdaExpression.Parameters.CastToArray();

            var nestedContext = context.CreateNew(variables, true);

            var method = nestedContext.HasCapturedVariablesArgument
                ? new DynamicMethod(string.Empty, lambdaExpression.ReturnType, nestedContext.HasCapturedVariablesArgument
                    ? new[] { nestedContext.Target.TargetType, nestedContext.CapturedArgumentsHolder.TargetType }.Append(nestedParameters.GetTypes())
                    : nestedContext.Target.TargetType.Append(parameters.GetTypes()), nestedContext.Target.TargetType, true)
                : new DynamicMethod(string.Empty, lambdaExpression.ReturnType, nestedContext.Target.TargetType.Append(nestedParameters.GetTypes()), nestedContext.Target.TargetType, true);

            var nestedGenerator = method.GetILGenerator();

            if (variables.Length > 0)
            {
                nestedContext.LocalBuilders = BuildLocals(variables, nestedGenerator);
            }

            if (nestedContext.HasCapturedVariablesArgument)
            {
                nestedGenerator.CopyParametersToCapturedArgumentsIfAny(nestedContext, nestedParameters);
            }

            if (!lambdaExpression.Body.TryEmit(nestedGenerator, nestedContext, nestedParameters))
            {
                return(false);
            }

            nestedGenerator.Emit(OpCodes.Ret);

            if (nestedContext.HasCapturedVariablesArgument)
            {
                var delegateArgs = nestedContext.CapturedArgumentsHolder.TargetType
                                   .Append(nestedParameters.GetTypes())
                                   .Append(lambdaExpression.ReturnType);

                var resultDelegate = method.CreateDelegate(Utils.MapDelegateType(delegateArgs),
                                                           nestedContext.Target.Target);

                nestedContext.Target.Fields[lambdaClosureIndex].SetValue(nestedContext.Target.Target, resultDelegate);

                if (nestedContext.HasCapturedVariablesArgument)
                {
                    generator.EmitMethod(Utils.GetMapperMethodInfo(delegateArgs));
                }
            }
            else
            {
                var resultDelegate = method.CreateDelegate(lambdaExpression.Type, nestedContext.Target.Target);
                nestedContext.Target.Fields[lambdaClosureIndex].SetValue(nestedContext.Target.Target, resultDelegate);
            }

            return(true);
        }
Beispiel #2
0
        private static bool TryEmit(this LambdaExpression expression, ILGenerator generator, CompilerContext context)
        {
            var lambdaIndex = context.NestedLambdas.IndexAndValueOf(expression, out var lambda);

            if (lambdaIndex == -1)
            {
                return(false);
            }

            var lambdaClosureIndex = lambdaIndex + (context.Target.Constants.Length - context.NestedLambdas.Length);

            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, Closure.ConstantsField);
            generator.EmitInteger(lambdaClosureIndex);
            generator.Emit(OpCodes.Ldelem_Ref);

            if (lambda.UsesCapturedArgument)
            {
                if (!context.IsNestedLambda)
                {
                    generator.Emit(OpCodes.Ldloc, context.CapturedArgumentsHolderVariable);
                }
                else
                {
                    generator.Emit(OpCodes.Ldarg_1);
                }
            }

            var variables        = lambda.ParameterExpressions;
            var nestedParameters = expression.Parameters.CastToArray();

            var nestedContext = context.CreateNew(variables, true, lambda.UsesCapturedArgument);

            var method = new DynamicMethod(string.Empty,
                                           expression.ReturnType,
                                           nestedContext.HasCapturedVariablesArgument
                        ? new[] { Utils.ClosureType, Utils.ObjectArrayType }.Append(nestedParameters.GetTypes())
                        : Utils.ClosureType.Append(nestedParameters.GetTypes()),
                                           Utils.ClosureType,
                                           true);

            var nestedGenerator = method.GetILGenerator();

            if (variables.Length > 0)
            {
                nestedContext.LocalBuilders = variables.BuildLocals(nestedGenerator);
            }

            if (nestedContext.HasCapturedVariablesArgument)
            {
                nestedGenerator.CopyParametersToCapturedArgumentsIfAny(nestedContext, nestedParameters);
            }

            if (!expression.Body.TryEmit(nestedGenerator, nestedContext, nestedParameters))
            {
                return(false);
            }

            nestedGenerator.Emit(OpCodes.Ret);

            if (nestedContext.HasCapturedVariablesArgument)
            {
                var delegateArgs = Utils.ObjectArrayType
                                   .Append(nestedParameters.GetTypes())
                                   .Append(expression.ReturnType);

                var resultDelegate = method.CreateDelegate(Utils.MapDelegateType(delegateArgs),
                                                           nestedContext.Target);

                nestedContext.Target.Constants[lambdaClosureIndex] = resultDelegate;

                if (nestedContext.HasCapturedVariablesArgument)
                {
                    generator.EmitMethod(Utils.GetPartialApplicationMethodInfo(delegateArgs));
                }
            }
            else
            {
                var resultDelegate = method.CreateDelegate(expression.Type, nestedContext.Target);
                nestedContext.Target.Constants[lambdaClosureIndex] = resultDelegate;
            }

            return(true);
        }