예제 #1
0
        private static void CreateConstructor(HandlerClassBuildingContext classContext)
        {
            const int thisArgIndex           = 0;
            const int codecContainerArgIndex = 1;

            var constructorBuilder = classContext.Builder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.Standard, new[] { typeof(ICodecContainer) });
            var baseConstructor = typeof(object).GetConstructor(Type.EmptyTypes);
            var il = new MyILGenerator(constructorBuilder.GetILGenerator());

            il.Ldarg(thisArgIndex);
            il.Call(baseConstructor);
            il.Ldarg(thisArgIndex);
            il.Ldarg(codecContainerArgIndex);
            il.Stfld(classContext.Fields.CodecContainer);

            foreach (var manualCodecField in classContext.Fields.GetAllManualCodecFields())
            {
                il.Ldarg(thisArgIndex);
                il.Ldarg(codecContainerArgIndex);
                il.Call(CodecContainerMethods.GetManualCodecFor(manualCodecField.FieldType.GenericTypeArguments[0]));
                il.Stfld(manualCodecField);
            }

            il.Ret();
        }
예제 #2
0
        private static void CreateConstructor(HandlerClassBuildingContext classContext)
        {
            const int thisArgIndex = 0;
            const int codecContainerArgIndex = 1;

            var constructorBuilder = classContext.Builder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.Standard, new[] { typeof(ICodecContainer) });
            var baseConstructor = typeof(object).GetConstructor(Type.EmptyTypes);
            var il = new MyILGenerator(constructorBuilder.GetILGenerator());
            il.Ldarg(thisArgIndex);
            il.Call(baseConstructor);
            il.Ldarg(thisArgIndex);
            il.Ldarg(codecContainerArgIndex);
            il.Stfld(classContext.Fields.CodecContainer);

            foreach (var manualCodecField in classContext.Fields.GetAllManualCodecFields())
            {
                il.Ldarg(thisArgIndex);
                il.Ldarg(codecContainerArgIndex);
                il.Call(CodecContainerMethods.GetManualCodecFor(manualCodecField.FieldType.GenericTypeArguments[0]));
                il.Stfld(manualCodecField);
            }

            il.Ret();
        }
예제 #3
0
        private static void EmitProcessAndEncodeAsyncWithRetval(HandlerClassBuildingContext classContext, IEmittingContext emittingContext, Type pureRetvalType)
        {
            var encodeDeferredMethod = CreateEncodeDeferredMethod(classContext, pureRetvalType);
            var continueWithMethod   = TaskMethods.ContinueWith(pureRetvalType, typeof(byte[]));

            var il = emittingContext.IL;

            il.Ldarg(0);
            il.Ldftn(encodeDeferredMethod);
            il.Newobj(FuncMethods.Constructor(typeof(Task <>).MakeGenericType(pureRetvalType), typeof(byte[])));
            il.Callvirt(continueWithMethod);
        }
예제 #4
0
        private static MethodBuilder CreateEncodeDeferredMethod(HandlerClassBuildingContext classContext, Type pureRetvalType)
        {
            const int taskArgIndex = 1;

            var methodBuilder = classContext.Builder.DefineMethod("EncodeDeferred",
                                                                  MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
                                                                  typeof(byte[]), new[] { typeof(Task <>).MakeGenericType(pureRetvalType) });

            var il = new MyILGenerator(methodBuilder.GetILGenerator());
            var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields);

            il.Ldarg(taskArgIndex);
            il.Call(TaskMethods.GetResult(pureRetvalType));
            EmitEncodeDirect(emittingContext, new HandlerParameterCodec[0], pureRetvalType);
            il.Ret();
            return(methodBuilder);
        }
예제 #5
0
        private Type CreateType(IReadOnlyList <ServiceDescription> serviceDescriptionChain, MethodDescription methodDescription, ServicePath path)
        {
            int disambiguator = Interlocked.Increment(ref classNameDisambiguator);
            var typeBuilder   = moduleBuilder.DefineType("__rpc_handler_" + string.Join(".", path) + "_" + disambiguator,
                                                         TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                                                         typeof(object), new[] { typeof(IHandler) });

            var genericTypeParameterBuilders = methodDescription.GenericParameters.Any()
                ? typeBuilder.DefineGenericParameters(methodDescription.GenericParameters.Select(x => x.Name).ToArray())
                : new GenericTypeParameterBuilder[0];

            var fieldCache   = new HandlerClassFieldCache(typeBuilder);
            var classContext = new HandlerClassBuildingContext(serviceDescriptionChain, methodDescription, typeBuilder, genericTypeParameterBuilders, fieldCache);

            CreateMethodDelegate(classContext);
            CreateConstructor(classContext);

            return(typeBuilder.CreateType());
        }
예제 #6
0
        private static void CreateMethodDelegate(HandlerClassBuildingContext classContext)
        {
            const int implementationArgIndex = 1;
            const int dataArgIndex           = 2;
            const int offsetArgIndex         = 3;

            var methodBuilder = classContext.Builder.DefineMethod("Handle",
                                                                  MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                                  MethodAttributes.NewSlot | MethodAttributes.Virtual,
                                                                  typeof(Task <byte[]>), new[] { typeof(object), typeof(byte[]), typeof(int) });

            var il = new MyILGenerator(methodBuilder.GetILGenerator());
            var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields);

            var serviceDescriptionChain = classContext.ServiceDescriptionChain;

            il.Ldarg(implementationArgIndex);                                       // stack_0 = (TServiceImplementation) arg_1
            il.Castclass(serviceDescriptionChain.First().Type);

            for (int i = 0; i < serviceDescriptionChain.Count - 1; i++)
            {
                var current = serviceDescriptionChain[i];
                var next    = serviceDescriptionChain[i + 1];
                il.Callvirt(current.Type.GetProperty(next.Name).GetGetMethod());    // stack_0 = stack_0.Property
            }

            var methodDescription = classContext.MethodDescription;

            var genericArgumentMap = methodDescription.GenericParameters
                                     .Zip(classContext.GenericTypeParameterBuilders, (p, a) => new KeyValuePair <string, Type>(p.Name, a))
                                     .ToDictionary(x => x.Key, x => x.Value);

            var parameterDescriptions = methodDescription.Parameters.Select(x => x.DeepSubstituteGenerics(genericArgumentMap)).ToArray();
            var retvalType            = methodDescription.ReturnType.DeepSubstituteGenerics(genericArgumentMap);

            var allParameterCodecs      = parameterDescriptions.Select((x, i) => new HandlerParameterCodec(emittingContext, x)).ToArray();
            var requestParameterCodecs  = allParameterCodecs.Where(x => x.IsRequestParameter).ToArray();
            var responseParameterCodecs = allParameterCodecs.Where(x => x.IsResponseParameter).ToArray();

            if (requestParameterCodecs.Any())
            {
                il.Ldarg(dataArgIndex);                                 // remainingBytes = dataArray.Length - offset
                il.Ldlen();
                il.Ldarg(offsetArgIndex);
                il.Sub();
                il.Stloc(emittingContext.RemainingBytesVar);
                var pinnedVar = il.PinArray(typeof(byte), 2);           // var pinned dataPointer = pin(dataArray)
                il.Ldloc(pinnedVar);                                    // data = dataPointer + offset
                il.Ldarg(offsetArgIndex);
                il.Add();
                il.Stloc(emittingContext.DataPointerVar);
            }

            foreach (var codec in allParameterCodecs)
            {
                codec.EmitDecodeAndPrepare();
            }

            // ReSharper disable CoVariantArrayConversion
            var resolvedMethodInfo = classContext.GenericTypeParameterBuilders.Any()
                ? methodDescription.MethodInfo.MakeGenericMethod(classContext.GenericTypeParameterBuilders)
                : methodDescription.MethodInfo;

            il.Callvirt(resolvedMethodInfo);                            // stack_0 = stack_0.Method(stack_1, stack_2, ...)
            // ReSharper restore CoVariantArrayConversion

            switch (methodDescription.RemotingType)
            {
            case MethodRemotingType.Direct:
                EmitProcessAndEncodeDirect(emittingContext, responseParameterCodecs, retvalType);
                break;

            case MethodRemotingType.AsyncVoid:
                EmitProcessAndEncodeAsyncVoid(emittingContext);
                break;

            case MethodRemotingType.AsyncWithRetval:
                EmitProcessAndEncodeAsyncWithRetval(classContext, emittingContext, retvalType.GetGenericArguments()[0]);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            il.Ret();
        }
예제 #7
0
        private Type CreateType(IReadOnlyList<ServiceDescription> serviceDescriptionChain, MethodDescription methodDescription, ServicePath path)
        {
            int disambiguator = Interlocked.Increment(ref classNameDisambiguator);
            var typeBuilder = moduleBuilder.DefineType("__rpc_handler_" + string.Join(".", path) + "_" + disambiguator,
                                            TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                                            typeof(object), new[] { typeof(IHandler) });

            var genericTypeParameterBuilders = methodDescription.GenericParameters.Any()
                ? typeBuilder.DefineGenericParameters(methodDescription.GenericParameters.Select(x => x.Name).ToArray())
                : new GenericTypeParameterBuilder[0];

            var fieldCache = new HandlerClassFieldCache(typeBuilder);
            var classContext = new HandlerClassBuildingContext(serviceDescriptionChain, methodDescription, typeBuilder, genericTypeParameterBuilders, fieldCache);

            CreateMethodDelegate(classContext);
            CreateConstructor(classContext);

            return typeBuilder.CreateType();
        }
예제 #8
0
        private static void EmitProcessAndEncodeAsyncWithRetval(HandlerClassBuildingContext classContext, IEmittingContext emittingContext, Type pureRetvalType)
        {
            var encodeDeferredMethod = CreateEncodeDeferredMethod(classContext, pureRetvalType);
            var continueWithMethod = TaskMethods.ContinueWith(pureRetvalType, typeof(byte[]));

            var il = emittingContext.IL;
            il.Ldarg(0);
            il.Ldftn(encodeDeferredMethod);
            il.Newobj(FuncMethods.Constructor(typeof(Task<>).MakeGenericType(pureRetvalType), typeof(byte[])));
            il.Callvirt(continueWithMethod);
        }
예제 #9
0
        private static void CreateMethodDelegate(HandlerClassBuildingContext classContext)
        {
            const int implementationArgIndex = 1;
            const int dataArgIndex = 2;
            const int offsetArgIndex = 3;

            var methodBuilder = classContext.Builder.DefineMethod("Handle",
                    MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                    MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    typeof(Task<byte[]>), new[] { typeof(object), typeof(byte[]), typeof(int) });

            var il = new MyILGenerator(methodBuilder.GetILGenerator());
            var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields);

            var serviceDescriptionChain = classContext.ServiceDescriptionChain;

            il.Ldarg(implementationArgIndex);                                       // stack_0 = (TServiceImplementation) arg_1
            il.Castclass(serviceDescriptionChain.First().Type);

            for (int i = 0; i < serviceDescriptionChain.Count - 1; i++)
            {
                var current = serviceDescriptionChain[i];
                var next = serviceDescriptionChain[i + 1];
                il.Callvirt(current.Type.GetProperty(next.Name).GetGetMethod());    // stack_0 = stack_0.Property
            }

            var methodDescription = classContext.MethodDescription;

            var genericArgumentMap = methodDescription.GenericParameters
                .Zip(classContext.GenericTypeParameterBuilders, (p, a) => new KeyValuePair<string, Type>(p.Name, a))
                .ToDictionary(x => x.Key, x => x.Value);

            var parameterDescriptions = methodDescription.Parameters.Select(x => x.DeepSubstituteGenerics(genericArgumentMap)).ToArray();
            var retvalType = methodDescription.ReturnType.DeepSubstituteGenerics(genericArgumentMap);

            var allParameterCodecs = parameterDescriptions.Select((x, i) => new HandlerParameterCodec(emittingContext, x)).ToArray();
            var requestParameterCodecs = allParameterCodecs.Where(x => x.IsRequestParameter).ToArray();
            var responseParameterCodecs = allParameterCodecs.Where(x => x.IsResponseParameter).ToArray();

            if (requestParameterCodecs.Any())
            {
                il.Ldarg(dataArgIndex);                                 // remainingBytes = dataArray.Length - offset
                il.Ldlen();
                il.Ldarg(offsetArgIndex);
                il.Sub();
                il.Stloc(emittingContext.RemainingBytesVar);
                var pinnedVar = il.PinArray(typeof(byte), 2);           // var pinned dataPointer = pin(dataArray)
                il.Ldloc(pinnedVar);                                    // data = dataPointer + offset
                il.Ldarg(offsetArgIndex);
                il.Add();
                il.Stloc(emittingContext.DataPointerVar);
            }

            foreach (var codec in allParameterCodecs)
                codec.EmitDecodeAndPrepare();

            // ReSharper disable CoVariantArrayConversion
            var resolvedMethodInfo = classContext.GenericTypeParameterBuilders.Any()
                ? methodDescription.MethodInfo.MakeGenericMethod(classContext.GenericTypeParameterBuilders)
                : methodDescription.MethodInfo;
            il.Callvirt(resolvedMethodInfo);                            // stack_0 = stack_0.Method(stack_1, stack_2, ...)
            // ReSharper restore CoVariantArrayConversion

            switch (methodDescription.RemotingType)
            {
                case MethodRemotingType.Direct:
                    EmitProcessAndEncodeDirect(emittingContext, responseParameterCodecs, retvalType);
                    break;
                case MethodRemotingType.AsyncVoid:
                    EmitProcessAndEncodeAsyncVoid(emittingContext);
                    break;
                case MethodRemotingType.AsyncWithRetval:
                    EmitProcessAndEncodeAsyncWithRetval(classContext, emittingContext, retvalType.GetGenericArguments()[0]);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            il.Ret();
        }
예제 #10
0
        private static MethodBuilder CreateEncodeDeferredMethod(HandlerClassBuildingContext classContext, Type pureRetvalType)
        {
            const int taskArgIndex = 1;

            var methodBuilder = classContext.Builder.DefineMethod("EncodeDeferred",
                MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
                typeof(byte[]), new[] {typeof(Task<>).MakeGenericType(pureRetvalType)});

            var il = new MyILGenerator(methodBuilder.GetILGenerator());
            var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields);

            il.Ldarg(taskArgIndex);
            il.Call(TaskMethods.GetResult(pureRetvalType));
            EmitEncodeDirect(emittingContext, new HandlerParameterCodec[0], pureRetvalType);
            il.Ret();
            return methodBuilder;
        }