public void Trivial()
        {
            var implementationInfo = new ServiceImplementationInfo();
            var path = new ServicePath("MyService", "MyMethod");
            var handler = (ServiceMethodHandler)((i, d) => new byte[0]);
            factory.CreateMethodHandler(implementationInfo, path).Returns(handler);

            var handler1 = container.GetMethodHandler(implementationInfo, path);
            var handler2 = container.GetMethodHandler(implementationInfo, path);

            Assert.That(handler1, Is.EqualTo(handler2));
        }
        public ServiceMethodHandler CreateMethodHandler(ServiceImplementationInfo serviceImplementationInfo, ServicePath servicePath)
        {
            var serviceInterface = serviceImplementationInfo.Interface;

            var dynamicMethod = new DynamicMethod(
                "__srpc__handle__" + serviceInterface.FullName + "__" + string.Join("_", servicePath),
                typeof(byte[]), ParameterTypes, Assembly.GetExecutingAssembly().ManifestModule);
            var il = dynamicMethod.GetILGenerator();
            var locals = new LocalVariableCollection(il, true);

            il.Emit(OpCodes.Ldarg_0);                                           // stack_0 = (TServiceImplementation) arg_0
            il.Emit(OpCodes.Castclass, serviceInterface);

            var serviceDesc = serviceImplementationInfo.Description;
            for (int i = 1; i < servicePath.Length - 1; i++)
            {
                var propertyInfo = serviceDesc.Type.GetProperty(servicePath[i]);
                il.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod());         // stack_0 = stack_0.Property
                SubserviceDescription subserviceDescription;
                if (!serviceDesc.TryGetSubservice(servicePath[i], out subserviceDescription))
                    throw new InvalidPathException();
                serviceDesc = subserviceDescription.Service;
            }

            var methodName = servicePath.MethodName;
            var methodInfo = serviceDesc.Type.GetMethod(methodName);
            MethodDescription methodDesc;
            if (!serviceDesc.TryGetMethod(methodName, out methodDesc))
                throw new InvalidPathException();

            bool hasRetval = methodDesc.ReturnType != typeof(void);
            var parameters = methodDesc.Parameters.Select((x, i) => new ParameterNecessity
                {
                    Description = x,
                    Codec = codecContainer.GetEmittingCodecFor(x.Type),
                    LocalVariable = x.Way != MethodParameterWay.Val ? il.DeclareLocal(x.Type) : null,
                    ArgumentIndex = i
                })
                .ToArray();

            var requestParameters = parameters
                    .Where(x => x.Description.Way == MethodParameterWay.Val || x.Description.Way == MethodParameterWay.Ref)
                    .ToArray();

            var responseParameters = parameters
                .Where(x => x.Description.Way == MethodParameterWay.Ref || x.Description.Way == MethodParameterWay.Out)
                .ToArray();

            LocalBuilder requestDataPointerVar = null;
            if (requestParameters.Any())
            {
                il.Emit(OpCodes.Ldarg_1);                                   // remainingBytes = arg_1.Length
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Stloc, locals.RemainingBytes);
                requestDataPointerVar =                                     // var pinned dataPointer = pin(arg_1)
                    il.Emit_PinArray(typeof(byte), locals, 1);
                il.Emit(OpCodes.Ldloc, requestDataPointerVar);              // data = dataPointer
                il.Emit(OpCodes.Stloc, locals.DataPointer);
            }

            foreach (var parameter in parameters)
            {
                switch (parameter.Description.Way)
                {
                    case MethodParameterWay.Val:
                        parameter.Codec.EmitDecode(il, locals, false);      // stack_i = decode(data, remainingBytes, false)
                        break;
                    case MethodParameterWay.Ref:
                        parameter.Codec.EmitDecode(il, locals, false);      // param_i = decode(data, remainingBytes, false)
                        il.Emit(OpCodes.Stloc, parameter.LocalVariable);
                        il.Emit(OpCodes.Ldloca, parameter.LocalVariable);   // stack_i = *param_i
                        break;
                    case MethodParameterWay.Out:
                        il.Emit(OpCodes.Ldloca, parameter.LocalVariable);   // stack_i = *param_i
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            if (requestParameters.Any())
            {
                il.Emit_UnpinArray(requestDataPointerVar);                  // unpin(dataPointer)
            }

            il.Emit(OpCodes.Callvirt, methodInfo);                          // stack_0 = stack_0.Method(stack_1, stack_2, ...)

            if (hasRetval || responseParameters.Any())
            {
                IEmittingCodec retvalCodec = null;
                LocalBuilder retvalVar = null;

                if (hasRetval)
                {
                    retvalCodec = codecContainer.GetEmittingCodecFor(methodDesc.ReturnType);
                    retvalVar = il.DeclareLocal(methodDesc.ReturnType);             // var ret = stack_0
                    il.Emit(OpCodes.Stloc, retvalVar);
                    retvalCodec.EmitCalculateSize(il, retvalVar);                   // stack_0 = calculateSize(ret)
                }

                bool hasSizeOnStack = hasRetval;
                foreach (var parameter in responseParameters)
                {
                    parameter.Codec.EmitCalculateSize(il, parameter.LocalVariable); // stack_0 += calculateSize(param_i)
                    if (hasSizeOnStack)
                        il.Emit(OpCodes.Add);
                    else
                        hasSizeOnStack = true;
                }

                var dataArrayVar = il.DeclareLocal(typeof(byte[]));                 // var dataArray = new byte[size of retval]
                il.Emit(OpCodes.Newarr, typeof(byte));
                il.Emit(OpCodes.Stloc, dataArrayVar);

                var responseDataPointerVar =                                        // var pinned dataPointer = pin(dataArrayVar)
                        il.Emit_PinArray(typeof(byte), locals, dataArrayVar);
                il.Emit(OpCodes.Ldloc, responseDataPointerVar);                     // data = dataPointer
                il.Emit(OpCodes.Stloc, locals.DataPointer);

                foreach (var parameter in responseParameters)
                    parameter.Codec.EmitEncode(il, locals, parameter.LocalVariable);// encode(data, param_i)

                if (hasRetval)
                    retvalCodec.EmitEncode(il, locals, retvalVar);                  // encode(data, ret)

                il.Emit_UnpinArray(responseDataPointerVar);                         // unpin(dataPointer)
                il.Emit(OpCodes.Ldloc, dataArrayVar);                               // stack_0 = dataArray
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, 0);                                         // stack_0 = new byte[0]
                il.Emit(OpCodes.Newarr, typeof(byte));
            }

            il.Emit(OpCodes.Ret);
            return (ServiceMethodHandler)dynamicMethod.CreateDelegate(typeof(ServiceMethodHandler));
        }
Ejemplo n.º 3
0
        public ServiceMethodHandler CreateMethodHandler(ServiceImplementationInfo serviceImplementationInfo, ServicePath servicePath)
        {
            var serviceInterface = serviceImplementationInfo.Description.Type;

            var dynamicMethod = new DynamicMethod(
                "__srpc__handle__" + serviceInterface.FullName + "__" + string.Join("_", servicePath),
                typeof(byte[]), ParameterTypes, Assembly.GetExecutingAssembly().ManifestModule, true);
            var il     = dynamicMethod.GetILGenerator();
            var locals = new LocalVariableCollection(il, true);

            il.Emit(OpCodes.Ldarg_0);                                           // stack_0 = (TServiceImplementation) arg_0
            il.Emit(OpCodes.Castclass, serviceInterface);

            var serviceDesc = serviceImplementationInfo.Description;

            for (int i = 1; i < servicePath.Length - 1; i++)
            {
                var propertyInfo = serviceDesc.Type.GetProperty(servicePath[i]);
                il.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod());         // stack_0 = stack_0.Property
                SubserviceDescription subserviceDescription;
                if (!serviceDesc.TryGetSubservice(servicePath[i], out subserviceDescription))
                {
                    throw new InvalidPathException();
                }
                serviceDesc = subserviceDescription.Service;
            }

            var methodName = servicePath.MethodName;
            MethodDescription methodDesc;

            if (!serviceDesc.TryGetMethod(methodName, out methodDesc))
            {
                throw new InvalidPathException();
            }

            bool hasRetval  = methodDesc.ReturnType != typeof(void);
            var  parameters = methodDesc.Parameters.Select((x, i) => new ParameterNecessity
            {
                Description   = x,
                Codec         = codecContainer.GetEmittingCodecFor(x.Type),
                LocalVariable = x.Way != MethodParameterWay.Val ? il.DeclareLocal(x.Type) : null,
                ArgumentIndex = i
            })
                              .ToArray();

            var requestParameters = parameters
                                    .Where(x => x.Description.Way == MethodParameterWay.Val || x.Description.Way == MethodParameterWay.Ref)
                                    .ToArray();

            var responseParameters = parameters
                                     .Where(x => x.Description.Way == MethodParameterWay.Ref || x.Description.Way == MethodParameterWay.Out)
                                     .ToArray();

            LocalBuilder requestDataPointerVar = null;

            if (requestParameters.Any())
            {
                il.Emit(OpCodes.Ldarg_1);                                   // remainingBytes = arg_1.Length
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Stloc, locals.RemainingBytes);
                requestDataPointerVar =                                     // var pinned dataPointer = pin(arg_1)
                                        il.Emit_PinArray(typeof(byte), 1);
                il.Emit(OpCodes.Ldloc, requestDataPointerVar);              // data = dataPointer
                il.Emit(OpCodes.Stloc, locals.DataPointer);
            }

            foreach (var parameter in parameters)
            {
                switch (parameter.Description.Way)
                {
                case MethodParameterWay.Val:
                    parameter.Codec.EmitDecode(il, locals, false);          // stack_i = decode(data, remainingBytes, false)
                    break;

                case MethodParameterWay.Ref:
                    parameter.Codec.EmitDecode(il, locals, false);          // param_i = decode(data, remainingBytes, false)
                    il.Emit(OpCodes.Stloc, parameter.LocalVariable);
                    il.Emit(OpCodes.Ldloca, parameter.LocalVariable);       // stack_i = *param_i
                    break;

                case MethodParameterWay.Out:
                    il.Emit(OpCodes.Ldloca, parameter.LocalVariable);       // stack_i = *param_i
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (requestParameters.Any())
            {
                il.Emit_UnpinArray(requestDataPointerVar);                  // unpin(dataPointer)
            }

            il.Emit(OpCodes.Callvirt, methodDesc.MethodInfo);                          // stack_0 = stack_0.Method(stack_1, stack_2, ...)

            if (hasRetval || responseParameters.Any())
            {
                IEmittingCodec retvalCodec = null;
                LocalBuilder   retvalVar   = null;

                if (hasRetval)
                {
                    retvalCodec = codecContainer.GetEmittingCodecFor(methodDesc.ReturnType);
                    retvalVar   = il.DeclareLocal(methodDesc.ReturnType);           // var ret = stack_0
                    il.Emit(OpCodes.Stloc, retvalVar);
                    retvalCodec.EmitCalculateSize(il, retvalVar);                   // stack_0 = calculateSize(ret)
                }

                bool hasSizeOnStack = hasRetval;
                foreach (var parameter in responseParameters)
                {
                    parameter.Codec.EmitCalculateSize(il, parameter.LocalVariable); // stack_0 += calculateSize(param_i)
                    if (hasSizeOnStack)
                    {
                        il.Emit(OpCodes.Add);
                    }
                    else
                    {
                        hasSizeOnStack = true;
                    }
                }

                var dataArrayVar = il.DeclareLocal(typeof(byte[]));                 // var dataArray = new byte[size of retval]
                il.Emit(OpCodes.Newarr, typeof(byte));
                il.Emit(OpCodes.Stloc, dataArrayVar);

                var responseDataPointerVar =                                        // var pinned dataPointer = pin(dataArrayVar)
                                             il.Emit_PinArray(typeof(byte), dataArrayVar);
                il.Emit(OpCodes.Ldloc, responseDataPointerVar);                     // data = dataPointer
                il.Emit(OpCodes.Stloc, locals.DataPointer);

                foreach (var parameter in responseParameters)
                {
                    parameter.Codec.EmitEncode(il, locals, parameter.LocalVariable);// encode(data, param_i)
                }
                if (hasRetval)
                {
                    retvalCodec.EmitEncode(il, locals, retvalVar);                  // encode(data, ret)
                }
                il.Emit_UnpinArray(responseDataPointerVar);                         // unpin(dataPointer)
                il.Emit(OpCodes.Ldloc, dataArrayVar);                               // stack_0 = dataArray
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, 0);                                         // stack_0 = new byte[0]
                il.Emit(OpCodes.Newarr, typeof(byte));
            }

            il.Emit(OpCodes.Ret);
            return((ServiceMethodHandler)dynamicMethod.CreateDelegate(typeof(ServiceMethodHandler)));
        }
Ejemplo n.º 4
0
 public ServiceMethodHandler GetMethodHandler(ServiceImplementationInfo serviceImplementationInfo, ServicePath servicePath)
 {
     return(handlers.GetOrAdd(servicePath, p => factory.CreateMethodHandler(serviceImplementationInfo, p)));
 }
 public void Setup()
 {
     codecContainer = new CodecContainer();
     factory = new ServiceMethodHandlerFactory(codecContainer);
     service = Substitute.For<IGlobalServiceImplementation>();
     var serviceDescriptionBuilder = new ServiceDescriptionBuilder(new MethodDescriptionBuilder());
     var globalServiceDescription =  serviceDescriptionBuilder.Build(typeof(IGlobalService));
     globalServiceImplementationInfo =
         new ServiceImplementationInfo(typeof(IGlobalService), globalServiceDescription, service);
 }
 public ServiceMethodHandler GetMethodHandler(ServiceImplementationInfo serviceImplementationInfo, ServicePath servicePath)
 {
     return handlers.GetOrAdd(servicePath, p => factory.CreateMethodHandler(serviceImplementationInfo, p));
 }