< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.InvokerUtil
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/InvokerUtil.cs
Line coverage
48%
Covered lines: 73
Uncovered lines: 76
Coverable lines: 149
Total lines: 335
Line coverage: 48.9%
Branch coverage
34%
Covered branches: 16
Total branches: 46
Branch coverage: 34.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/InvokerUtil.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Linq.Expressions;
 8using System.Reflection;
 9using System.Runtime.ExceptionServices;
 10using System.Text;
 11using CoreWCF.Description;
 12using Microsoft.Extensions.Logging;
 13
 14namespace CoreWCF.Dispatcher
 15{
 16    internal delegate object InvokeDelegate(object target, object[] inputs, object[] outputs);
 17
 18    internal delegate IAsyncResult InvokeBeginDelegate(object target, object[] inputs, AsyncCallback asyncCallback, obje
 19
 20    internal delegate object InvokeEndDelegate(object target, object[] outputs, IAsyncResult result);
 21
 22    internal delegate object CreateInstanceDelegate();
 23
 24    internal static class InvokerUtil
 25    {
 626        private static readonly string s_useLegacyInvokeDelegateAppContextSwitchKey = "CoreWCF.Dispatcher.UseLegacyInvok
 627        private static readonly string s_isDynamicCodeSupportedAppContextSwitchKey = "System.Runtime.CompilerServices.Ru
 28
 629        private static readonly Lazy<bool> s_isDynamicCodeSupported = new Lazy<bool>(() =>
 630            // See https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtim
 631            AppContext.TryGetSwitch(s_isDynamicCodeSupportedAppContextSwitchKey, out bool isDynamicCodeSupported)
 632                ? isDynamicCodeSupported
 633                : true
 634        );
 35
 636        private static readonly Lazy<bool> s_useLegacyInvokeDelegate = new Lazy<bool>(() =>
 637            AppContext.TryGetSwitch(s_useLegacyInvokeDelegateAppContextSwitchKey, out bool useLegacyInvokeDelegate)
 638                ? useLegacyInvokeDelegate
 639                : false
 640        );
 41
 42        private const BindingFlags DefaultBindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.P
 43        // private readonly CriticalHelper _helper;
 44
 45        //public InvokerUtil()
 46        //{
 47        //    _helper = new CriticalHelper();
 48        //}
 49
 50        internal static bool HasDefaultConstructor(Type type)
 51        {
 44752            return type.GetConstructor(DefaultBindingFlags, null, Type.EmptyTypes, null) != null;
 53        }
 54
 55        internal static CreateInstanceDelegate GenerateCreateInstanceDelegate(Type type)
 56        {
 34357            return CriticalHelper.GenerateCreateInstanceDelegate(type);
 58        }
 59
 60        internal static InvokeDelegate GenerateInvokeDelegate(ILogger<InvokeDelegate> logger, MethodInfo method, out int
 61            out int outputParameterCount)
 62        {
 4963            return CriticalHelper.GenerateInvokeDelegate(logger, method, out inputParameterCount, out outputParameterCou
 64        }
 65
 66        //internal InvokeBeginDelegate GenerateInvokeBeginDelegate(MethodInfo method, out int inputParameterCount)
 67        //{
 68        //    return helper.GenerateInvokeBeginDelegate(method, out inputParameterCount);
 69        //}
 70
 71        //internal InvokeEndDelegate GenerateInvokeEndDelegate(MethodInfo method, out int outputParameterCount)
 72        //{
 73        //    return helper.GenerateInvokeEndDelegate(method, out outputParameterCount);
 74        //}
 75
 76        private static class CriticalHelper
 77        {
 78            internal static CreateInstanceDelegate GenerateCreateInstanceDelegate(Type type)
 79            {
 34380                if (type.GetTypeInfo().IsValueType)
 81                {
 082                    MethodInfo method = typeof(CriticalHelper).GetMethod(nameof(CreateInstanceOfStruct),
 083                    BindingFlags.NonPublic | BindingFlags.Static);
 084                    MethodInfo generic = method.MakeGenericMethod(type);
 085                    return (CreateInstanceDelegate)generic.CreateDelegate(typeof(CreateInstanceDelegate));
 86                }
 87                else
 88                {
 34389                    MethodInfo method = typeof(CriticalHelper).GetMethod(nameof(CreateInstanceOfClass),
 34390                    BindingFlags.NonPublic | BindingFlags.Static);
 34391                    MethodInfo generic = method.MakeGenericMethod(type);
 34392                    return (CreateInstanceDelegate)generic.CreateDelegate(typeof(CreateInstanceDelegate));
 93                }
 94            }
 95
 96            internal static object CreateInstanceOfClass<T>() where T : class, new()
 97            {
 55698                return new T();
 99            }
 100
 101            internal static object CreateInstanceOfStruct<T>() where T : struct
 102            {
 0103                return default(T);
 104            }
 105
 106            internal static InvokeDelegate GenerateInvokeDelegate(ILogger<InvokeDelegate> logger, MethodInfo method, out
 49107                (!s_useLegacyInvokeDelegate.Value && s_isDynamicCodeSupported.Value)
 49108                ? GenerateInvokeDelegateInternalWithExpressions(logger, method, out inputParameterCount, out outputParam
 49109                : GenerateInvokeDelegateInternal(method, out inputParameterCount, out outputParameterCount);
 110
 111            private static InvokeDelegate GenerateInvokeDelegateInternal(MethodInfo method, out int inputParameterCount,
 112            {
 0113                ParameterInfo[] parameters = method.GetParameters();
 0114                bool returnsValue = method.ReturnType != typeof(void);
 0115                int paramCount = parameters.Length;
 116
 0117                var inputParamPositions = new List<int>();
 0118                var outputParamPositions = new List<int>();
 119
 0120                for (int i = 0; i < parameters.Length; i++)
 121                {
 0122                    if (ServiceReflector.FlowsIn(parameters[i]))
 123                    {
 0124                        inputParamPositions.Add(i);
 125                    }
 126
 0127                    if (ServiceReflector.FlowsOut(parameters[i]))
 128                    {
 0129                        outputParamPositions.Add(i);
 130                    }
 131                }
 132
 0133                int[] inputPos = inputParamPositions.ToArray();
 0134                int[] outputPos = outputParamPositions.ToArray();
 135
 0136                inputParameterCount = inputPos.Length;
 0137                outputParameterCount = outputPos.Length;
 138
 0139                return delegate (object target, object[] inputs, object[] outputs)
 0140                {
 0141                    object[] paramsLocal = null;
 0142                    if (paramCount > 0)
 0143                    {
 0144                        paramsLocal = new object[paramCount];
 0145
 0146                        for (int i = 0; i < inputPos.Length; i++)
 0147                        {
 0148                            paramsLocal[inputPos[i]] = inputs[i];
 0149                        }
 0150                    }
 0151
 0152                    object result = null;
 0153                    try
 0154                    {
 0155                        if (returnsValue)
 0156                        {
 0157                            result = method.Invoke(target, paramsLocal);
 0158                        }
 0159                        else
 0160                        {
 0161                            method.Invoke(target, paramsLocal);
 0162                        }
 0163                    }
 0164                    catch (TargetInvocationException tie)
 0165                    {
 0166                        ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
 0167                    }
 0168
 0169                    for (int i = 0; i < outputPos.Length; i++)
 0170                    {
 0171                        Debug.Assert(paramsLocal != null);
 0172                        outputs[i] = paramsLocal[outputPos[i]];
 0173                    }
 0174
 0175                    return result;
 0176                };
 177            }
 178
 179            private static InvokeDelegate GenerateInvokeDelegateInternalWithExpressions(ILogger<InvokeDelegate> logger, 
 180            {
 49181                inputParameterCount = 0;
 49182                outputParameterCount = 0;
 49183                ParameterInfo[] parameters = method.GetParameters();
 49184                bool returnsValue = method.ReturnType != typeof(void);
 49185                bool returnsValueType = method.ReturnType.IsValueType;
 186
 49187                var targetParam = Expression.Parameter(typeof(object), "target");
 49188                var inputsParam = Expression.Parameter(typeof(object[]), "inputs");
 49189                var outputsParam = Expression.Parameter(typeof(object[]), "outputs");
 190
 49191                List<ParameterExpression> variables = new();
 49192                var result = Expression.Variable(typeof(object), "result");
 49193                variables.Add(result);
 194
 49195                List<(Type ParameterType, ParameterExpression OutputExpression)> outputVariables = new();
 49196                List<ParameterExpression> invocationParameters = new();
 49197                List<Expression> expressions = new();
 198
 136199                for (int i = 0; i < parameters.Length; i++)
 200                {
 19201                    Type variableType = parameters[i].ParameterType.IsByRef
 19202                        ? parameters[i].ParameterType.GetElementType()
 19203                        : parameters[i].ParameterType;
 19204                    ParameterExpression variable = Expression.Variable(variableType, $"p{i}");
 205
 19206                    if (ServiceReflector.FlowsIn(parameters[i]))
 207                    {
 19208                        var inputParamValue =
 19209                            Expression.ArrayIndex(inputsParam, Expression.Constant(inputParameterCount));
 19210                        var convertValueToType = Expression.Convert(inputParamValue, variableType);
 19211                        var defaultValue = Expression.Default(variableType);
 19212                        var convertOrGetDefault = Expression.Condition(Expression.Equal(inputParamValue, Expression.Cons
 19213                            defaultValue, convertValueToType);
 19214                        expressions.Add(Expression.Assign(variable, convertOrGetDefault));
 19215                        inputParameterCount++;
 216                    }
 217
 19218                    if (ServiceReflector.FlowsOut(parameters[i]))
 219                    {
 0220                        outputParameterCount++;
 0221                        outputVariables.Add((variableType, variable));
 222                    }
 223
 19224                    variables.Add(variable);
 19225                    invocationParameters.Add(variable);
 226                }
 227
 49228                var castTargetParam = Expression.Convert(targetParam, method.DeclaringType);
 229
 49230                if (returnsValue)
 231                {
 35232                    if (returnsValueType)
 233                    {
 0234                        expressions.Add(Expression.Assign(result, Expression.Convert(Expression.Call(castTargetParam, me
 235                    }
 236                    else
 237                    {
 35238                        expressions.Add(Expression.Assign(result, Expression.Call(castTargetParam, method, invocationPar
 239                    }
 240                }
 241                else
 242                {
 14243                    expressions.Add(Expression.Call(castTargetParam, method, invocationParameters));
 14244                    expressions.Add(Expression.Assign(result, Expression.Constant(null, typeof(object))));
 245                }
 246
 49247                int j = 0;
 98248                foreach (var outputVariable in outputVariables)
 249                {
 0250                    if (outputVariable.ParameterType.IsValueType)
 251                    {
 0252                        expressions.Add(Expression.Assign(
 0253                            Expression.ArrayAccess(outputsParam, Expression.Constant(j)),
 0254                            Expression.Convert(outputVariable.OutputExpression, typeof(object))));
 255                    }
 256                    else
 257                    {
 0258                        expressions.Add(Expression.Assign(
 0259                            Expression.ArrayAccess(outputsParam, Expression.Constant(j)),
 0260                            outputVariable.OutputExpression));
 261                    }
 0262                    j++;
 263                }
 264
 49265                expressions.Add(result);
 266
 49267                BlockExpression finalBlock = Expression.Block(variables: variables, expressions: expressions);
 268
 49269                Expression<InvokeDelegate> lambda = Expression.Lambda<InvokeDelegate>(
 49270                    finalBlock,
 49271                    targetParam,
 49272                    inputsParam,
 49273                    outputsParam);
 274
 49275                if (logger.IsEnabled(LogLevel.Debug))
 276                {
 0277                    var expr = GetDebugString(finalBlock).Trim();
 0278                    logger.LogDebug("{methodType} {method}\n{expr}", method.DeclaringType, method.ToString(), expr);
 279                }
 280
 49281                return lambda.Compile();
 282
 283                string GetDebugString(Expression expr)
 284                {
 0285                    if (expr is BlockExpression block)
 286                    {
 0287                        StringBuilder sb = new();
 0288                        foreach (var e in block.Expressions)
 289                        {
 0290                            sb.AppendLine(GetDebugString(e));
 291                        }
 0292                        return sb.ToString();
 293                    }
 294                    else
 295                    {
 0296                        return expr.ToString();
 297                    }
 298                }
 299            }
 300
 301            //public InvokeBeginDelegate GenerateInvokeBeginDelegate(MethodInfo method, out int inputParameterCount)
 302            //{
 303            //    ParameterInfo[] parameters = method.GetParameters();
 304            //    var inputCount = parameters.Length;
 305            //    inputParameterCount = inputCount;
 306
 307            //    InvokeBeginDelegate lambda =
 308            //        delegate(object target, object[] inputs, AsyncCallback callback, object state)
 309            //        {
 310            //            object[] inputsLocal = new object[inputCount];
 311            //            for (var i = 0; i < inputCount; i++)
 312            //            {
 313            //                inputsLocal[i] = inputs[i];
 314            //            }
 315            //            inputsLocal[inputCount] = callback;
 316            //            inputsLocal[inputCount + 1] = state;
 317            //            object result = method.Invoke(target, inputs);
 318            //            return result as IAsyncResult;
 319            //        };
 320
 321            //    return lambda;
 322            //}
 323
 324            //public InvokeEndDelegate GenerateInvokeEndDelegate(MethodInfo method, out int outParameterCount)
 325            //{
 326
 327            //    InvokeEndDelegate lambda =
 328            //        delegate(object target, object[] outputs, IAsyncResult result)
 329            //        {
 330
 331            //        }
 332            //}
 333        }
 334    }
 335}